diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,369 @@
+## 12.1.0 (2023.06.26)
+
++ Merge llvm-hs and llvm-hs-pure.
++ Fix the build
++ Add upper bounds to everything
+
+# llvm-hs changelog
+
+## 12.0.0 (2021-03-19)
+
+* Update to LLVM 12.0
+* Remove OrcJIT V1 bindings and replace them with OrcJIT V2.
+
+## 9.0.1 (2019-09-28)
+
+* Fix build with Clang on MacOS.
+* Expose `LLVMOffsetOfElement` as `getOffsetOfElement`.
+
+## 9.0.0 (2019-09-06)
+
+* Support GHC 8.8
+* Update to LLVM 9.0
+  * Note that this is the last LLVM release that supports the current
+    OrcJIT APIs and `llvm-hs` does not yet have bindings for OrcJIT
+    V2. If you are interested in working on that please get in
+    touch. See https://github.com/llvm-hs/llvm-hs/issues/276 for more
+    details.
+  * The `sanitizeAddresses` field from `MachineCodeOptions` has been
+    removed following a change in LLVM.
+  * The `MemorySanitizer` now has two new options `kernel` and
+    `recover` matching the options in LLVM.
+
+
+## 8.1.0
+
+* Change `withHostTargetMachine` to accept the code model, relocation model,
+  and optimization level as arguments. The old behaviour is available
+  under the name `withHostTargetMachineDefault`.
+
+## 8.0.0 (2019-03-10)
+
+* Upgrade to LLVM 8
+* It is now possible to define multiple variables with an empty name
+  without causing a name collision. Variables with an empty name
+  cannot be referenced. This fixes an issue caused by using
+  IRBuilder’s `extern` helper.
+
+## 7.0.1 (2018-09-29)
+
+* Support llvm-config executables named `llvm-config-7` in addition to
+  `llvm-config-7.0` and `llvm-config`.
+
+## 7.0.0 (2018-09-28)
+
+* Throw an `EncodeException` if a local variable is defined multiple
+  times. This is consistent with `llc` which also forbids reusing
+  variable names.
+* Update for LLVM 7.0:
+  * The ORC JIT API has been changed to reflect the changes in LLVM
+    itself. The test suite should give you a good idea of how to adapt
+    your code but here is a summary:
+    * There is now a separate `ExecutionSession` that tracks module handles.
+    * `SymbolResolver` only has a single resolver function.
+    * Creating an `ObjectLinkingLayer` requires a way to get the
+      symbol resolver for a module.
+    * Creating a `CompileOnDemandLayer` requires a way to set and get
+      the symbol resolver for a module.
+
+## 6.3.0 (2018-06-12)
+
+* `findSymbol` and `findSymbolIn` now return `Either JITSymbolError
+  JITSymbol` if the JIT symbol has the error flag set or the address
+  is 0. (This is consistent with how LLVM treats JIT symbols).
+* The return type of `SymbolResolverFn` has been changed to `Either
+  JITSymbolError JITSymbol`. It is fine to return a 0 address in
+  `Right` so existing resolvers can be adapted by wrapping the result
+  in `Right`.
+* Fixed a bug where instructions were constant-folded during
+  encoding. This caused problems since the API available on a Constant
+  is not the same as the one on an Instruction (e.g., we cannot set
+  metadata on a Constant).
+* Fix use-after-free in `createObjectFile`.
+* Add `withObjectFile` wrapper for `createObjectFile` and
+  `disposeObjectFile`.
+* Add API for looking up symbols in the `LinkingLayer`.
+* Add `LLVM.OrcJIT.CompileLayer` and `LLVM.OrcJIT.LinkingLayer`
+  modules that reexport the internal modules. The
+  `findSymbol/findSymbolIn` methods that have previously been exported
+  from `LLVM.OrcJIT` can now be found in `LLVM.OrcJIT.CompileLayer`.
+
+## 6.2.0 (2018-05-08)
+
+* Remove field prefixes from `DIDerivedType`, `DIBasicType` and
+  `DISubroutineType` to make the API consistent with the other debug
+  metadata types.
+* Change the type of the scope fields in `DIModule` and `DINamespace`
+  to `Maybe (MDRef DIScope)` to reflect that they can be optional.
+
+## 6.1.1 (2018-05-06)
+
+* Fix the source distribution by adding missing files to extra-source-files.
+
+## 6.1.0 (2018-05-05)
+
+* Remove the `MetadataNodeReference` constructor. References to
+  metadata nodes are now encoded using the polymorphic `MDRef` type.
+* Add support for encoding and decoding debug metadata. Thanks to
+  @xldenis who started that effort!
+* Drop support for GHC 7.10.
+* Support decoding/encoding of metadata in `GlobalVariable` and `Function`.
+* Fix check that the type of `GlobalReference` is correct in the
+  presence of automatic renamings due to name collisions.
+* Extract LinkingLayer into a separate module.
+
+## 6.0.0 (2018-03-06)
+
+* Support for LLVM 6.0, take a look at the changelog of llvm-hs-pure for details.
+* Add `AggregateZero` for zero-initializing structs, arrays and vectors. Previously `Null`
+  was used for null pointers as  well as zero-inializing aggregates. The new behavior reflects
+  LLVM’s internal representation and the C++-API.
+* Enforce that `Null` is only used on pointer types. Existing uses of `Null` on arrays, structs and
+  vector must be changed to the newly introduced `AggregateZero`.
+
+## 5.1.3 (2018-01-06)
+
+* Add bindings to `loadLibraryPermamently` and `getSymbolAddressInProcess`.
+
+## 5.1.2 (2017-12-19)
+
+* Reupload of 5.1.1 since [Hackage broke](https://github.com/haskell/hackage-server/issues/643) during the original upload.
+
+## 5.1.1 (2017-12-16)
+
+* Fix argument order in `LLVM_Hs_CreateTargetMachine`. This affects `withTargetMachine` and `withHostTargetMachine`.
+* Add support for `MCTargetOptions`.
+
+## 5.1.0 (2017-10-12)
+
+### Bugfixes
+
+* Set target options in `withTargetMachine`. Previously the options
+  passed there were simply ignored.
+* Fix decoding of constant vectors.
+* Fix decoding of function attributes in calls.
+
+### Enhancements
+
+* Support for more target options.
+* Suport string attributes as parameter attributes.
+* Support more calling conventions.
+* Support `NoTail` `TailCallKind`.
+
+## 5.0.0 (2017-09-07)
+
+* Support for LLVM 5.0
+
+    We only give a summary of the changes affecting the public API of `llvm-hs` here.
+    Please refer to the official
+    [release notes for LLVM 5.0](http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html)
+    for an overview of all changes in LLVM 5.0.
+
+    * The `X86_64_Win64` calling convention is now called `Win64`.
+    * There is a new `Speculatable` function attribute.
+    * The `CrossThread` synchronization scope has been removed. There is
+      now a new `System` synchronization scope.
+    * The `OrcJIT`-API now operates on individual modules instead of
+      sets of modules.
+    * The `lessPreciseFloatingPointMultiplyAddOption` field has been
+      removed from the target options.
+    * The `compressDebugSections` option field is now of type
+      `DebugCompressionType` instead of `Bool`.
+    * The `BasicBlockVectorize` pass has been removed. You should use
+      `SuperwordLevelParallelismVectorize` instead.
+
+* Throw 'EncodeException' when the type supplied in a
+  'GlobalReference' does not match the type of the expression.
+* Throw 'EncodeException' when the result of instructions returning
+  void is named using ':='.
+
+## 4.2.0 (2017-06-20)
+
+* Revamp OrcJIT API
+  * The user facing API is now exposed using `LLVM.OrcJIT`.
+  * All user facing functions have been documented.
+  * In addition the bracket-style API, there are now `new*` and
+    `dispose*` functions making it easier to ingegrate OrcJIT in
+    custom monad transformer stacks.
+  * There is a new `CompileLayer` typeclass which abstracts over the
+    various compile layers in `OrcJIT`.
+* Support QuickCheck 2.10
+
+## 4.1.0 (2017-05-17)
+
+* Switch most of the API from `String` to `ByteString`.
+* Switch from ExceptT to using exceptions.
+  See `LLVM.Exception` for an overview of the exceptions potentially thrown.
+
+## 4.0.1
+
+* Fix linking of system libraries
+
+## 4.0.0 (initial release, changes in comparison to llvm-general)
+
+* Move modules from `LLVM.General*` to `LLVM.*`
+* Support for LLVM 4.0
+* Improved support for LLVM’s exception handling instructions
+* `-fshared-llvm` is now supported on windows (thanks to @RyanGLScott)
+* Default to `-fshared-llvm`
+* Expose `LLVM.Internal.*` modules.
+
+# llvm-hs-pure changelog
+
+## 12.0.0 (2021-03-19)
+
+* Update to LLVM 12.0
+* Eliminate hard-coded assumption of 32-bit `size_t`
+* Add a runtime variant of the `LLVM.AST.Constant.sizeof` utility in `LLVM.IRBuilder.Instruction.sizeof`. The size of opaque structure types is unknown until link-time and therefore cannot be computed as a constant.
+* Handle type resolution through `NamedTypeReference` correctly: type resolution in LLVM depends on module state by design
+* Support the LLVM `NoFree` attribute
+* Add support for some more DWARF operators: `DW_OP_bregx` and `DW_OP_push_object_address`
+
+## 9.1.0 (UNRELEASED)
+
+* IRBuilder: first emitted terminator (`br`, `condBr`, `ret`, ...) is only
+  generated in final IR. This allows for greater composition of IR (and matches
+  with LLVM semantics, since later instructions are unreachable).
+
+## 9.0.0 (2019-09-06)
+
+* The functions in `LLVM.IRBuilder.Constant` no longer return a
+  monadic context. To recover the previous behavior use `pure`. (Thanks to @jfaure)
+* `LLVM.IRBuilder.Instruction.globalStringPtr` returns a `Constant`
+  instead of an `Operand`. (Thanks to @jfaure)
+* Fresh name generation in the IRBuilder should be significantly faster (Thanks to @luc-tielen)
+* Update to LLVM 9.0
+  * The `MainSubprogram` constructor from `DIFlag` has been removed
+    and a few new flags have been added.
+
+## 8.0.0 (2019-03-10)
+
+* Upgrade to LLVM 8
+* Change type of `value` field in `DITemplateValueParameter` to
+  `Maybe Metadata` to reflect that it can be null.
+
+## 7.0.0 (2018-09-28)
+
+* Track type definitions in `MonadModuleBuilder`. This allows us to
+  automatically resolve `NamedTypeReference`s in `gep` instructions.
+  Note that type definitions must be defined before they are used
+  (i.e. `MonadFix` will not behave correctly here).
+* Change the type of `gep` in the `IRBuilder` API to require a
+  `MonadModuleBuilder` constraint.
+* Change the type of `typedef` in the `IRBuilder` API to return a
+  `NamedTypeReference` to the newly defined type.
+* Update for LLVM 7.0:
+  * Add `isUnsigned` field to `DIEnumerator`.
+  * Change `DISubrange` to use the new `DICount` type instead of an `Int64`.
+  * Merge `checksum` and `checksumKind` fields of `DIFile` into a
+    `checksum` field of type `Maybe ChecksumInfo`.
+  * Rename the `variables` field of `DISubprogram` to `retainedNodes`.
+
+## 6.2.1 (2018-06-12)
+
+* Fix type of `shuffleVector` in the IRBuilder API.
+
+## 6.2.0 (2018-05-08)
+
+* Remove field prefixes from `DIDerivedType`, `DIBasicType` and
+  `DISubroutineType` to make the API consistent with the other debug
+  metadata types.
+* Change the type of the scope fields in `DIModule` and `DINamespace`
+  to `Maybe (MDRef DIScope)` to reflect that they can be optional.
+
+## 6.1.0 (2018-05-05)
+
+* IRBuilder: Ensure that automatically generated block labels are
+  assigned smaller identifiers than the instructions following
+  them. This is only important when you use
+  `llvm-hs-pretty`. `llvm-hs` does not care about the order of
+  identifiers assigned to unnamed values.
+* IRBuilder: add `currentBlock` which returns name of the currently
+  active block.
+* Remove the `MetadataNodeReference` constructor. References to
+  metadata nodes are now encoded using the polymorphic `MDRef` type.
+* Add debug metadata to the AST in `LLVM.AST.Operand`. Thanks to
+  @xldenis who started that effort!
+* Drop support for GHC 7.10.
+* Add `metadata` field to `GlobalVariable` and `Function`.
+
+## 6.0.0 (2018-03-06)
+
+* Support for LLVM 6.0
+  * Add `StrictFP` and `SanitizeHWAddress` function attributes.
+  * Remove `UnsafeAlgebra` constructor from `FastMathFlags`.
+  * Add `allowReassoc`, `allowContract` and `approxFunc` fields to `FastMathFlags`.
+  * Remove `NoFastMathFlags` constructor since it is equivalent to
+    setting all fields in the `FastMathFlags` record to
+    `False`. Existing uses of `NoFastMathFlags` can be replaced by the
+    `noFastMathFlags` value.
+* Add `AggregateZero` for zero-initializing structs, arrays and vectors. Previously `Null`
+  was used for null pointers as  well as zero-inializing aggregates. The new behavior reflects
+  LLVM’s internal representation and the C++-API. Existing uses of `Null` on non-pointer types
+  must be changed to `AggregateZero`.
+* Fix recursive function calls in the `IRBuilder` API.
+
+## 5.1.2 (2018-01-06)
+
+* Fixes and enhancements to the IRBuilder
+  * `sdiv` and `udiv` no longer default to exact.
+  * Fix type of global references.
+  * Add more instructions.
+
+
+## 5.1.1 (2017-12-16)
+
+* Add a completely new API for building modules in a monadic style similar to the IRBuilder provided by LLVM’s C++ API. The modules can be found in `LLVM.IRBuilder`. An example can be found in the readme and in the test suite.
+* Add an API for getting the type of LLVM values in
+  `LLVM.AST.Typed`. This is primarily intended to be used in other
+  libraries that build upon `llvm-hs-pure` such as `llvm-hs-pretty`.
+
+## 5.1.0 (2017-10-12)
+
+### Enhancements
+
+* Suport string attributes as parameter attributes
+* Support more calling conventions
+* Support `NoTail` `TailCallKind`
+
+## 5.0.0 (2017-09-07)
+
+* Support for LLVM 5.0
+
+    We only give a summary of the changes affecting the public API of `llvm-hs-pure` here.
+    Please refer to the official
+    [release notes for LLVM 5.0](http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html)
+    for an overview of all changes in LLVM 5.0.
+
+    * The `X86_64_Win64` calling convention is now called `Win64`.
+    * There is a new `Speculatable` function attribute.
+    * The `CrossThread` synchronization scope has been removed. There is
+      now a new `System` synchronization scope.
+
+## 4.1.0 (2017-05-17)
+
+* Switch AST to `ByteString`/`ShortByteString` reflecting LLVM’s use
+  of C-style strings.
+* `preferredAlignment` is now a `Word32` instead of `Maybe Word32`. To
+  recover the old behavior set it to the same value as abiAlignment.
+* `GlobalAlias` now expects the element type of a pointer type instead
+  of the pointer type itself. The address space is passed separately
+  via the `addrSpace` field. This makes `GlobalAlias` consistent with
+  `GlobalVariable`.
+* The `FloatingPointType` constructor now takes a `FloatingPointType` argument
+  instead of a width and a `FloatingPointFormat` to more closely match the
+  LLVM IR language reference.
+* The `IsString` instance of `Name` now throws an error on non-ASCII
+  strings instead of silently discarding the upper bytes. There is
+  also a new `mkName` function with the same behavior for easier
+  discoverability. Non-ASCII names need to be encoded using an arbitrary encoding to
+  to a `ShortByteString` which can then be used as a `Name`.
+
+## 4.0.0 (initial release, changes in comparison to llvm-general)
+
+* Move modules from `LLVM.General*` to `LLVM.*`
+* Support for LLVM 4.0
+* Improved support for LLVM’s exception handling instructions
+* `-fshared-llvm` is now supported on windows (thanks to @RyanGLScott)
+* Default to `-fshared-llvm`
+* Expose `LLVM.Internal.*` modules.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2013, Benjamin S. Scarlet and Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Benjamin S. Scarlet nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,88 @@
+# llvm-party - Haskell bindings for LLVM
+
+[![Build Status](https://travis-ci.org/llvm-hs/llvm-hs.svg?branch=llvm-6)](https://travis-ci.org/llvm-hs/llvm-hs) [![Hackage](https://img.shields.io/hackage/v/llvm-hs.svg)](https://hackage.haskell.org/package/llvm-hs)
+
+This project aims to provide a relatively complete set of bindings for
+the LLVM API. If you find that anything is missing please open an
+issue! We generally try to stay close to the LLVM C++-API so you can
+consult the LLVM documentation and reuse existing resources.
+
+This is yet [another](https://hackage.haskell.org/package/llvm-tf) [fork](https://hackage.haskell.org/package/llvm) [of](https://hackage.haskell.org/package/llvm-hs) [llvm](https://hackage.haskell.org/package/llvm-general).
+Specifically [llvm-hs](https://hackage.haskell.org/package/llvm-hs)/[llvm-hs-pure](https://hackage.haskell.org/package/llvm-hs-pure)
+was forked, and smashed together into a single package.
+
+## Getting started
+
+If you’ve worked with LLVM before, take a look at the examples in the
+[llvm-hs-examples repo](https://github.com/llvm-hs/llvm-hs-examples).
+If not, you can find a translation of the [official LLVM
+tutorial](http://llvm.org/docs/tutorial/#kaleidoscope-implementing-a-language-with-llvm)
+at https://github.com/llvm-hs/llvm-hs-kaleidoscope. There is also a
+[blog series](https://blog.josephmorag.com/tags/llvm/) on writing a C
+compiler with the library. In general, we try to stay very close to
+the API and AST provided by LLVM itself, so the [LLVM language
+reference](http://llvm.org/docs/LangRef.html) is also very useful.
+
+## LLVM API Interface
+
+`llvm-hs` provides an LLVM binding at (roughly) the same level of abstraction
+as the official LLVM C API. Because of this, anything you might do with the
+LLVM C API, you should expect to be able to do with `llvm-hs`. In addition,
+some things which are not handled in the LLVM C API are supported. For example,
+the LLVM C API [does not provide any
+support](https://llvm.org/doxygen/group__LLVMCSupportTypes.html) for working
+with `AttributeSet` and `AttributeList` types, but `llvm-hs` does.
+
+However, the binding to LLVM is only half the story: a lot of advanced
+pure-Haskell functionality is built on top of this basic interface in the
+`llvm-hs-pure` module, most notably the monadic
+[IRBuilder](https://hackage.haskell.org/package/llvm-hs-pure) and
+[ModuleBuilder](https://hackage.haskell.org/package/llvm-hs-pure) interfaces
+which greatly simplify the task of generating LLVM code from a higher level
+abstract syntax. The
+[llvm-hs-examples](https://github.com/llvm-hs/llvm-hs-examples/blob/master/irbuilder/Main.hs)
+project contains example usage. These high level interfaces are ideal for
+implementing the LLVM backend for your code generation project. A good example
+is Google's [Dex](https://github.com/google-research/dex-lang) research
+language.
+
+## LLVM API Coverage and Philosophy
+
+The `llvm-hs` FFI layer in `LLVM/Internal/FFI` extends the upstream LLVM C API
+*adding missing functionality* which upstream has not yet exposed from the C++
+API. We also provide some *improved implementations* of buggy or otherwise
+problematic functions in the LLVM C API. As the LLVM C API becomes more
+complete, we retire our extensions and directly wrap the newly added C API
+functions, ensuring our FFI layer is as small as possible.
+
+If you find you need to use some LLVM functionality which is available via the
+C++ API but not via the C API or in  `llvm-hs`, please open an issue and
+include links to the relevant entities in the LLVM doxygen-generated
+documentation.
+
+In general, if it is possible to implement something in Haskell using the LLVM
+C API primitives, that is preferable to implementing things in the FFI layer
+and merely exposing them to Haskell as wrapped C or C++ functions.
+
+## Contributing
+
+We love all kinds of contributions so please feel free to open issues for
+missing LLVM features, report & fix bugs or report API inconveniences.
+
+## Versioning
+
+Trying to represent the version of LLVM in the version number but also
+allowing for version bumps in the bindings themselves while respecting
+the [PVP](http://pvp.haskell.org/) can be tricky. Luckily LLVM switched to a
+[new versioning scheme](http://blog.llvm.org/2016/12/llvms-new-versioning-scheme.html)
+of `major.0.patch` starting from version `4.0`. This means that we can
+use the last two components for these bindings while the first
+component indicates the version of LLVM. A special case are the
+versions `3.major.minor` that represent bindings to LLVM 3.9. Bindings
+to earlier versions are not provided.
+
+## How is this related to llvm-general?
+
+This project is a fork of the venerable `llvm-general` that aims to improve the
+public release story, and better provide the interfaces needed for any Haskell
+project looking to leverage LLVM. Contributions are encouraged.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,200 @@
+{-# LANGUAGE CPP, FlexibleInstances #-}
+import Control.Exception (SomeException, try)
+import Control.Monad
+import Data.Char
+import Data.List
+import Data.Maybe
+import Data.Monoid
+import Distribution.PackageDescription hiding (buildInfo, includeDirs)
+import Distribution.Simple
+import Distribution.Simple.LocalBuildInfo
+import Distribution.Simple.PreProcess
+import Distribution.Simple.Program
+import Distribution.Simple.Setup hiding (Flag)
+import Distribution.System
+import System.Environment
+
+#ifdef MIN_VERSION_Cabal
+#if MIN_VERSION_Cabal(2,0,0)
+#define MIN_VERSION_Cabal_2_0_0
+#endif
+#endif
+
+-- define these selectively in C files (we are _not_ using HsFFI.h),
+-- rather than universally in the ccOptions, because HsFFI.h currently defines them
+-- without checking they're already defined and so causes warnings.
+uncheckedHsFFIDefines :: [String]
+uncheckedHsFFIDefines = ["__STDC_LIMIT_MACROS"]
+
+#ifndef MIN_VERSION_Cabal_2_0_0
+mkVersion :: [Int] -> Version
+mkVersion ver = Version ver []
+versionNumbers :: Version -> [Int]
+versionNumbers = versionBranch
+mkFlagName :: String -> FlagName
+mkFlagName = FlagName
+#endif
+
+#if !(MIN_VERSION_Cabal(2,1,0))
+lookupFlagAssignment :: FlagName -> FlagAssignment -> Maybe Bool
+lookupFlagAssignment = lookup
+#endif
+
+llvmVersion :: Version
+llvmVersion = mkVersion [12,0]
+
+-- Ordered by decreasing specificty so we will prefer llvm-config-9.0
+-- over llvm-config-9 over llvm-config.
+llvmConfigNames :: [String]
+llvmConfigNames = reverse versionedConfigs ++ ["llvm-config"]
+  where
+    versionedConfigs =
+      map
+        (\vs -> "llvm-config-" ++ intercalate "." (map show vs))
+        (tail (inits (versionNumbers llvmVersion)))
+
+findJustBy :: Monad m => (a -> m (Maybe b)) -> [a] -> m (Maybe b)
+findJustBy f (x:xs) = do
+  x' <- f x
+  case x' of
+    Nothing -> findJustBy f xs
+    j -> return j
+findJustBy _ [] = return Nothing
+
+llvmProgram :: Program
+llvmProgram = (simpleProgram "llvm-config") {
+  programFindLocation = \v p -> findJustBy (\n -> programFindLocation (simpleProgram n) v p) llvmConfigNames,
+  programFindVersion = \verbosity path ->
+    let
+      stripVcsSuffix = takeWhile (\c -> isDigit c || c == '.')
+      trim = dropWhile isSpace . reverse . dropWhile isSpace . reverse
+    in findProgramVersion "--version" (stripVcsSuffix . trim) verbosity path
+ }
+
+getLLVMConfig :: ConfigFlags -> IO ([String] -> IO String)
+getLLVMConfig confFlags = do
+  let verbosity = fromFlag $ configVerbosity confFlags
+  (program, _, _) <- requireProgramVersion verbosity llvmProgram
+                     (withinVersion llvmVersion)
+                     (configPrograms confFlags)
+  return $ getProgramOutput verbosity program
+
+addToLdLibraryPath :: String -> IO ()
+addToLdLibraryPath path = do
+  let (ldLibraryPathVar, ldLibraryPathSep) =
+        case buildOS of
+          OSX -> ("DYLD_LIBRARY_PATH",":")
+          _ -> ("LD_LIBRARY_PATH",":")
+  v <- try $ getEnv ldLibraryPathVar :: IO (Either SomeException String)
+  setEnv ldLibraryPathVar (path ++ either (const "") (ldLibraryPathSep ++) v)
+
+addLLVMToLdLibraryPath :: ConfigFlags -> IO ()
+addLLVMToLdLibraryPath confFlags = do
+  llvmConfig <- getLLVMConfig confFlags
+  [libDir] <- liftM lines $ llvmConfig ["--libdir"]
+  addToLdLibraryPath libDir
+
+-- | These flags are not relevant for us and dropping them allows
+-- linking against LLVM build with Clang using GCC
+ignoredCxxFlags :: [String]
+ignoredCxxFlags = ["-fcolor-diagnostics"] ++ map ("-D" ++) uncheckedHsFFIDefines
+
+ignoredCFlags :: [String]
+ignoredCFlags = ["-fcolor-diagnostics"]
+
+-- | Header directories are added separately to configExtraIncludeDirs
+isIncludeFlag :: String -> Bool
+isIncludeFlag flag = "-I" `isPrefixOf` flag
+
+isWarningFlag :: String -> Bool
+isWarningFlag flag = "-W" `isPrefixOf` flag
+
+isIgnoredCFlag :: String -> Bool
+isIgnoredCFlag flag = flag `elem` ignoredCFlags || isIncludeFlag flag || isWarningFlag flag
+
+isIgnoredCxxFlag :: String -> Bool
+isIgnoredCxxFlag flag = flag `elem` ignoredCxxFlags || isIncludeFlag flag || isWarningFlag flag
+
+main :: IO ()
+main = do
+  let origUserHooks = simpleUserHooks
+
+  defaultMainWithHooks origUserHooks {
+    hookedPrograms = [ llvmProgram ],
+
+    confHook = \(genericPackageDescription, hookedBuildInfo) confFlags -> do
+      llvmConfig <- getLLVMConfig confFlags
+      llvmCxxFlags <- do
+        rawLlvmCxxFlags <- llvmConfig ["--cxxflags"]
+        return . filter (not . isIgnoredCxxFlag) $ words rawLlvmCxxFlags
+      let stdLib = maybe "stdc++"
+                         (drop (length stdlibPrefix))
+                         (find (isPrefixOf stdlibPrefix) llvmCxxFlags)
+            where stdlibPrefix = "-stdlib=lib"
+      includeDirs <- liftM lines $ llvmConfig ["--includedir"]
+      libDirs <- liftM lines $ llvmConfig ["--libdir"]
+      [llvmVersion] <- liftM lines $ llvmConfig ["--version"]
+      let getLibs = liftM (map (fromJust . stripPrefix "-l") . words) . llvmConfig
+          flags    = configConfigurationsFlags confFlags
+          linkFlag = case lookupFlagAssignment (mkFlagName "shared-llvm") flags of
+                       Nothing     -> "--link-shared"
+                       Just shared -> if shared then "--link-shared" else "--link-static"
+      libs       <- getLibs ["--libs", linkFlag]
+      systemLibs <- getLibs ["--system-libs", linkFlag]
+
+      let genericPackageDescription' = genericPackageDescription {
+            condLibrary = do
+              libraryCondTree <- condLibrary genericPackageDescription
+              return libraryCondTree {
+                condTreeData = condTreeData libraryCondTree <> mempty {
+                    libBuildInfo =
+                      mempty {
+                        ccOptions = llvmCxxFlags,
+                        extraLibs = libs ++ stdLib : systemLibs
+                      }
+                  }
+              }
+           }
+          configFlags' = confFlags {
+            configExtraLibDirs = libDirs ++ configExtraLibDirs confFlags,
+            configExtraIncludeDirs = includeDirs ++ configExtraIncludeDirs confFlags
+           }
+      addLLVMToLdLibraryPath configFlags'
+      confHook simpleUserHooks (genericPackageDescription', hookedBuildInfo) configFlags',
+
+    hookedPreProcessors =
+      let origHookedPreprocessors = hookedPreProcessors origUserHooks
+#ifdef MIN_VERSION_Cabal_2_0_0
+          newHsc buildInfo localBuildInfo componentLocalBuildInfo =
+#else
+          newHsc buildInfo localBuildInfo =
+#endif
+              ppUnlit {
+                  platformIndependent = platformIndependent (origHsc buildInfo),
+                  runPreProcessor = \inFiles outFiles verbosity -> do
+                      llvmConfig <- getLLVMConfig (configFlags localBuildInfo)
+                      llvmCFlags <- do
+                          rawLlvmCFlags <- llvmConfig ["--cflags"]
+                          return . filter (not . isIgnoredCFlag) $ words rawLlvmCFlags
+                      let buildInfo' = buildInfo { ccOptions = "-Wno-variadic-macros" : llvmCFlags }
+                      runPreProcessor (origHsc buildInfo') inFiles outFiles verbosity
+              }
+              where origHsc buildInfo' =
+                      fromMaybe
+                        ppHsc2hs
+                        (lookup "hsc" origHookedPreprocessors)
+                        buildInfo'
+                        localBuildInfo
+#ifdef MIN_VERSION_Cabal_2_0_0
+                        componentLocalBuildInfo
+#endif
+      in [("hsc", newHsc)] ++ origHookedPreprocessors,
+
+    buildHook = \packageDesc localBuildInfo userHooks buildFlags ->
+      do addLLVMToLdLibraryPath (configFlags localBuildInfo)
+         buildHook origUserHooks packageDesc localBuildInfo userHooks buildFlags,
+
+    testHook = \args packageDesc localBuildInfo userHooks testFlags ->
+      do addLLVMToLdLibraryPath (configFlags localBuildInfo)
+         testHook origUserHooks args packageDesc localBuildInfo userHooks testFlags
+   }
diff --git a/llvm-party.cabal b/llvm-party.cabal
new file mode 100644
--- /dev/null
+++ b/llvm-party.cabal
@@ -0,0 +1,346 @@
+cabal-version:      2.2
+name:               llvm-party
+version:            12.1.0
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:
+  Anthony Cowley, Stephen Diehl, Moritz Kiefer <moritz.kiefer@purelyfunctional.org>, Benjamin S. Scarlet
+
+maintainer:
+  Anthony Cowley, Stephen Diehl, Moritz Kiefer <moritz.kiefer@purelyfunctional.org>
+
+copyright:          (c) 2013 Benjamin S. Scarlet and Google Inc.
+homepage:           http://github.com/jappeace/llvm-party/
+bug-reports:        http://github.com/jappeace/llvm-party/issues
+build-type:         Custom
+stability:          experimental
+category:           Compilers/Interpreters, Code Generation
+synopsis:           General purpose LLVM bindings
+description:
+  llvm-party is a set of Haskell bindings for LLVM <http://llvm.org/>. Unlike other current Haskell bindings,
+  it uses an ADT to represent LLVM IR (<http://llvm.org/docs/LangRef.html>), and so offers two advantages: it
+  handles almost all of the stateful complexities of using the LLVM API to build IR; and it supports moving IR not
+  only from Haskell into LLVM C++ objects, but the other direction - from LLVM C++ into Haskell.
+  This is a fork of llvm-hs, with a major advantage that it's being maintained, for now.
+
+extra-source-files:
+  src/LLVM/Internal/FFI/Analysis.h
+  src/LLVM/Internal/FFI/Attribute.h
+  src/LLVM/Internal/FFI/AttributeC.hpp
+  src/LLVM/Internal/FFI/CallingConvention.h
+  src/LLVM/Internal/FFI/Constant.h
+  src/LLVM/Internal/FFI/ErrorHandling.hpp
+  src/LLVM/Internal/FFI/GlobalValue.h
+  src/LLVM/Internal/FFI/InlineAssembly.h
+  src/LLVM/Internal/FFI/Instruction.h
+  src/LLVM/Internal/FFI/LibFunc.h
+  src/LLVM/Internal/FFI/Metadata.h
+  src/LLVM/Internal/FFI/OrcJIT.h
+  src/LLVM/Internal/FFI/SMDiagnostic.h
+  src/LLVM/Internal/FFI/Target.h
+  src/LLVM/Internal/FFI/Target.hpp
+  src/LLVM/Internal/FFI/Type.h
+  src/LLVM/Internal/FFI/Value.h
+  test/debug_metadata_1.ll
+  test/debug_metadata_2.ll
+  test/debug_metadata_3.ll
+  test/debug_metadata_4.ll
+  test/debug_metadata_5.ll
+  test/main_return_38.c
+  README.md
+  LICENSE
+  CHANGELOG.md
+
+tested-with:        GHC ==8.8.1
+extra-source-files: CHANGELOG.md
+
+source-repository head
+  type:     git
+  location: git://github.com/jappeace/llvm-party.git
+  branch:   llvm-12
+
+flag shared-llvm
+  description: link against llvm shared rather than static library
+  default:     True
+
+flag llvm-with-rtti
+  description:
+    assume llvm was built with LLVM_ENABLE_RTTI=ON (default is OFF)
+
+  default:     False
+
+flag debug
+  description:
+    compile C(++) shims with debug info for ease of troubleshooting
+
+  default:     False
+
+custom-setup
+  setup-depends:
+    , base        <5
+    , Cabal       <3.10.1.0
+    , containers
+
+library
+  default-language:   Haskell2010
+  hs-source-dirs:     src
+  build-tool-depends: hsc2hs:hsc2hs
+  ghc-options:
+    -O2 -Wall -fno-warn-name-shadowing -fno-warn-orphans -optcxx=-O3
+    -optcxx=-Wall -optcxx=-std=c++14 -optcxx=-lstdc++
+
+  cxx-options:        -O3 -Wall -std=c++14
+
+  if flag(llvm-with-rtti)
+    cxx-options: -frtti
+    ghc-options: -optcxx=-frtti
+
+  else
+    cxx-options: -fno-rtti
+    ghc-options: -optcxx=-fno-rtti
+
+  if flag(debug)
+    cxx-options: -g
+    ghc-options: -optcxx=-g
+
+  extra-libraries:    stdc++
+  build-depends:
+    , array                 >=0.4.0.0 && <0.6
+    , attoparsec            >=0.13    && <0.15
+    , base                  >=4.9     && <5
+    , bytestring            >=0.10    && <0.12
+    , containers            >=0.4.2.1 && <0.7
+    , exceptions            >=0.8     && <0.11
+    , fail                  <4.10
+    , mtl                   >=2.1.3   && <2.3
+    , template-haskell      >=2.5.0.0 && <2.20
+    , transformers          >=0.3     && <0.6
+    , unordered-containers  >=0.2     && <0.3
+    , utf8-string           >=0.3.7   && <1.1
+
+  default-extensions:
+    NoImplicitPrelude
+    ConstraintKinds
+    DeriveDataTypeable
+    DeriveGeneric
+    EmptyDataDecls
+    FlexibleContexts
+    FlexibleInstances
+    StandaloneDeriving
+    TupleSections
+
+  exposed-modules:
+    LLVM
+    LLVM.Analysis
+    LLVM.AST
+    LLVM.AST.AddrSpace
+    LLVM.AST.Attribute
+    LLVM.AST.CallingConvention
+    LLVM.AST.COMDAT
+    LLVM.AST.Constant
+    LLVM.AST.DataLayout
+    LLVM.AST.DLL
+    LLVM.AST.Float
+    LLVM.AST.FloatingPointPredicate
+    LLVM.AST.FunctionAttribute
+    LLVM.AST.Global
+    LLVM.AST.InlineAssembly
+    LLVM.AST.Instruction
+    LLVM.AST.IntegerPredicate
+    LLVM.AST.Linkage
+    LLVM.AST.Name
+    LLVM.AST.Operand
+    LLVM.AST.ParameterAttribute
+    LLVM.AST.RMWOperation
+    LLVM.AST.ThreadLocalStorage
+    LLVM.AST.Type
+    LLVM.AST.Typed
+    LLVM.AST.Visibility
+    LLVM.CodeGenOpt
+    LLVM.CodeModel
+    LLVM.CommandLine
+    LLVM.Context
+    LLVM.DataLayout
+    LLVM.Diagnostic
+    LLVM.Exception
+    LLVM.ExecutionEngine
+    LLVM.Internal.Analysis
+    LLVM.Internal.Atomicity
+    LLVM.Internal.Attribute
+    LLVM.Internal.BasicBlock
+    LLVM.Internal.CallingConvention
+    LLVM.Internal.Coding
+    LLVM.Internal.CommandLine
+    LLVM.Internal.Constant
+    LLVM.Internal.Context
+    LLVM.Internal.DataLayout
+    LLVM.Internal.DecodeAST
+    LLVM.Internal.Diagnostic
+    LLVM.Internal.EncodeAST
+    LLVM.Internal.ExecutionEngine
+    LLVM.Internal.FastMathFlags
+    LLVM.Internal.FFI.Analysis
+    LLVM.Internal.FFI.Assembly
+    LLVM.Internal.FFI.Attribute
+    LLVM.Internal.FFI.BasicBlock
+    LLVM.Internal.FFI.BinaryOperator
+    LLVM.Internal.FFI.Bitcode
+    LLVM.Internal.FFI.Builder
+    LLVM.Internal.FFI.ByteRangeCallback
+    LLVM.Internal.FFI.Cleanup
+    LLVM.Internal.FFI.CommandLine
+    LLVM.Internal.FFI.Constant
+    LLVM.Internal.FFI.Context
+    LLVM.Internal.FFI.DataLayout
+    LLVM.Internal.FFI.DynamicLibrary
+    LLVM.Internal.FFI.ExecutionEngine
+    LLVM.Internal.FFI.Function
+    LLVM.Internal.FFI.GlobalAlias
+    LLVM.Internal.FFI.GlobalValue
+    LLVM.Internal.FFI.GlobalVariable
+    LLVM.Internal.FFI.InlineAssembly
+    LLVM.Internal.FFI.Instruction
+    LLVM.Internal.FFI.InstructionDefs
+    LLVM.Internal.FFI.Iterate
+    LLVM.Internal.FFI.LLVMCTypes
+    LLVM.Internal.FFI.MemoryBuffer
+    LLVM.Internal.FFI.Metadata
+    LLVM.Internal.FFI.Module
+    LLVM.Internal.FFI.ObjectFile
+    LLVM.Internal.FFI.OrcJIT
+    LLVM.Internal.FFI.PassManager
+    LLVM.Internal.FFI.PtrHierarchy
+    LLVM.Internal.FFI.RawOStream
+    LLVM.Internal.FFI.RTDyldMemoryManager
+    LLVM.Internal.FFI.ShortByteString
+    LLVM.Internal.FFI.SMDiagnostic
+    LLVM.Internal.FFI.Target
+    LLVM.Internal.FFI.Threading
+    LLVM.Internal.FFI.Transforms
+    LLVM.Internal.FFI.Type
+    LLVM.Internal.FFI.User
+    LLVM.Internal.FFI.Value
+    LLVM.Internal.FloatingPointPredicate
+    LLVM.Internal.Function
+    LLVM.Internal.Global
+    LLVM.Internal.InlineAssembly
+    LLVM.Internal.Instruction
+    LLVM.Internal.InstructionDefs
+    LLVM.Internal.IntegerPredicate
+    LLVM.Internal.LibraryFunction
+    LLVM.Internal.Linking
+    LLVM.Internal.MemoryBuffer
+    LLVM.Internal.Metadata
+    LLVM.Internal.Module
+    LLVM.Internal.ObjectFile
+    LLVM.Internal.Operand
+    LLVM.Internal.OrcJIT
+    LLVM.Internal.PassManager
+    LLVM.Internal.RawOStream
+    LLVM.Internal.RMWOperation
+    LLVM.Internal.String
+    LLVM.Internal.TailCallKind
+    LLVM.Internal.Target
+    LLVM.Internal.Threading
+    LLVM.Internal.Type
+    LLVM.Internal.Value
+    LLVM.IRBuilder
+    LLVM.IRBuilder.Constant
+    LLVM.IRBuilder.Instruction
+    LLVM.IRBuilder.Internal.SnocList
+    LLVM.IRBuilder.Module
+    LLVM.IRBuilder.Monad
+    LLVM.Linking
+    LLVM.Module
+    LLVM.OrcJIT
+    LLVM.PassManager
+    LLVM.Prelude
+    LLVM.Relocation
+    LLVM.Target
+    LLVM.Target.LibraryFunction
+    LLVM.Target.Options
+    LLVM.Threading
+    LLVM.Transforms
+    LLVM.Triple
+
+  other-modules:
+    Control.Monad.AnyCont
+    Control.Monad.AnyCont.Class
+    Control.Monad.Trans.AnyCont
+
+  include-dirs:       src
+  cxx-sources:
+    src/LLVM/Internal/FFI/AssemblyC.cpp
+    src/LLVM/Internal/FFI/AttributeC.cpp
+    src/LLVM/Internal/FFI/BitcodeC.cpp
+    src/LLVM/Internal/FFI/BuilderC.cpp
+    src/LLVM/Internal/FFI/CallingConventionC.cpp
+    src/LLVM/Internal/FFI/CommandLineC.cpp
+    src/LLVM/Internal/FFI/ConstantC.cpp
+    src/LLVM/Internal/FFI/ErrorHandling.cpp
+    src/LLVM/Internal/FFI/ExecutionEngineC.cpp
+    src/LLVM/Internal/FFI/FunctionC.cpp
+    src/LLVM/Internal/FFI/GlobalAliasC.cpp
+    src/LLVM/Internal/FFI/GlobalValueC.cpp
+    src/LLVM/Internal/FFI/InlineAssemblyC.cpp
+    src/LLVM/Internal/FFI/InstructionC.cpp
+    src/LLVM/Internal/FFI/MetadataC.cpp
+    src/LLVM/Internal/FFI/ModuleC.cpp
+    src/LLVM/Internal/FFI/OrcJITC.cpp
+    src/LLVM/Internal/FFI/PassManagerC.cpp
+    src/LLVM/Internal/FFI/RawOStreamC.cpp
+    src/LLVM/Internal/FFI/RTDyldMemoryManager.cpp
+    src/LLVM/Internal/FFI/SMDiagnosticC.cpp
+    src/LLVM/Internal/FFI/TargetC.cpp
+    src/LLVM/Internal/FFI/TypeC.cpp
+    src/LLVM/Internal/FFI/ValueC.cpp
+
+test-suite test
+  default-language:   Haskell2010
+  type:               exitcode-stdio-1.0
+  build-depends:
+    , base              >=4.9     && <5
+    , bytestring        >=0.10
+    , containers        >=0.4.2.1
+    , llvm-party
+    , mtl               >=2.1
+    , pretty-show       >=1.6
+    , process
+    , QuickCheck        >=2.5.1.1
+    , tasty             >=0.11
+    , tasty-hunit       >=0.9
+    , tasty-quickcheck  >=0.8
+    , temporary         >=1.2
+    , transformers      >=0.3.0.0
+
+  hs-source-dirs:     test
+  default-extensions:
+    FlexibleContexts
+    FlexibleInstances
+    TupleSections
+
+  main-is:            Test.hs
+  other-modules:
+    LLVM.Test.Analysis
+    LLVM.Test.Attribute
+    LLVM.Test.CallingConvention
+    LLVM.Test.Constants
+    LLVM.Test.DataLayout
+    LLVM.Test.ExecutionEngine
+    LLVM.Test.FunctionAttribute
+    LLVM.Test.Global
+    LLVM.Test.InlineAssembly
+    LLVM.Test.Instructions
+    LLVM.Test.Instrumentation
+    LLVM.Test.Linking
+    LLVM.Test.Metadata
+    LLVM.Test.Module
+    LLVM.Test.ObjectCode
+    LLVM.Test.Optimization
+    LLVM.Test.OrcJIT
+    LLVM.Test.ParameterAttribute
+    LLVM.Test.Regression
+    LLVM.Test.Support
+    LLVM.Test.Target
+    LLVM.Test.Tests
+    LLVM.Test.IRBuilder
diff --git a/src/Control/Monad/AnyCont.hs b/src/Control/Monad/AnyCont.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/AnyCont.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+module Control.Monad.AnyCont (
+    MonadAnyCont(..),
+    ScopeAnyCont(..),
+    AnyContT(..),
+    MonadTransAnyCont(..),
+    runAnyContT, runAnyContT',
+    withAnyContT,
+    mapAnyContT
+  ) where
+
+import Prelude
+
+import Control.Monad.Trans.AnyCont
+import Control.Monad.AnyCont.Class
+import Control.Monad.Trans.Class
+import Control.Monad.State.Class
+import Control.Monad.Error.Class
+
+instance MonadState s m => MonadState s (AnyContT m) where
+  get = lift get
+  {-# INLINE get #-}
+  put = lift . put
+  {-# INLINE put #-}
+  state = lift . state
+  {-# INLINE state #-}
+
+instance MonadError e m => MonadError e (AnyContT m) where
+  throwError = lift . throwError
+  {-# INLINE throwError #-}
+  x `catchError` h = anyContT $ \f -> (runAnyContT x f) `catchError` (\e -> runAnyContT (h e) f)
diff --git a/src/Control/Monad/AnyCont/Class.hs b/src/Control/Monad/AnyCont/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/AnyCont/Class.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE
+  RankNTypes,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+module Control.Monad.AnyCont.Class where
+
+import Prelude
+
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.AnyCont (AnyContT)
+import qualified Control.Monad.Trans.AnyCont as AnyCont
+import Control.Monad.Trans.Except as Except
+import Control.Monad.Trans.State as State
+
+class ScopeAnyCont m where
+  scopeAnyCont :: m a -> m a
+
+class MonadAnyCont b m where
+  anyContToM :: (forall r . (a -> b r) -> b r) -> m a
+
+
+instance MonadTransAnyCont b m => MonadAnyCont b (AnyContT m) where
+  anyContToM c = AnyCont.anyContT (liftAnyCont c)
+  {-# INLINE anyContToM #-}
+
+instance Monad m => ScopeAnyCont (AnyContT m) where
+  scopeAnyCont = lift . AnyCont.runAnyContT' return
+  {-# INLINE scopeAnyCont #-}
+
+
+instance (Monad m, MonadAnyCont b m) => MonadAnyCont b (StateT s m) where
+  anyContToM x = lift $ anyContToM x
+  {-# INLINE anyContToM #-}
+
+instance ScopeAnyCont m => ScopeAnyCont (StateT s m) where
+  scopeAnyCont = StateT . (scopeAnyCont .) . runStateT
+  {-# INLINE scopeAnyCont #-}
+
+
+instance (Monad m, MonadAnyCont b m) => MonadAnyCont b (ExceptT e m) where
+  anyContToM x = lift $ anyContToM x
+  {-# INLINE anyContToM #-}
+
+instance ScopeAnyCont m => ScopeAnyCont (ExceptT e m) where
+  scopeAnyCont = mapExceptT scopeAnyCont
+  {-# INLINE scopeAnyCont #-}
+
+
+class MonadTransAnyCont b m where
+  liftAnyCont :: (forall r . (a -> b r) -> b r) -> (forall r . (a -> m r) -> m r)
+
+instance MonadTransAnyCont b b where
+  liftAnyCont c = c
+  {-# INLINE liftAnyCont #-}
+
+instance MonadTransAnyCont b m => MonadTransAnyCont b (StateT s m) where
+  liftAnyCont c = (\c q -> StateT $ \s -> c $ ($ s) . runStateT . q) (liftAnyCont c)
+
+instance MonadTransAnyCont b m => MonadTransAnyCont b (ExceptT e m) where
+  liftAnyCont c = (\c q -> ExceptT . c $ runExceptT . q) (liftAnyCont c)
diff --git a/src/Control/Monad/Trans/AnyCont.hs b/src/Control/Monad/Trans/AnyCont.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Trans/AnyCont.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE
+  CPP, RankNTypes
+  #-}
+module Control.Monad.Trans.AnyCont where
+
+import LLVM.Prelude
+
+import Control.Monad.Catch
+import Control.Monad.Cont as Cont
+import Control.Monad.Fail as Fail
+
+newtype AnyContT m a = AnyContT { unAnyContT :: forall r . ContT r m a }
+
+instance Functor (AnyContT m) where
+  fmap f p = AnyContT $ fmap f (unAnyContT p)
+  {-# INLINE fmap #-}
+
+instance Applicative (AnyContT m) where
+  pure a = AnyContT $ pure a
+  {-# INLINE pure #-}
+  f <*> v = AnyContT $ unAnyContT f <*> unAnyContT v
+  {-# INLINE (<*>) #-}
+
+instance Monad m => Monad (AnyContT m) where
+  AnyContT f >>= k = AnyContT $ f >>= \x -> unAnyContT (k x)
+  {-# INLINE (>>=) #-}
+  return a = AnyContT $ return a
+  {-# INLINE return #-}
+#if !(MIN_VERSION_base(4,13,0))
+  fail s = AnyContT (ContT (\_ -> Cont.fail s))
+  {-# INLINE fail #-}
+#endif
+
+instance MonadFail m => MonadFail (AnyContT m) where
+  fail s = AnyContT (ContT (\_ -> Fail.fail s))
+  {-# INLINE fail #-}
+
+instance MonadIO m => MonadIO (AnyContT m) where
+  liftIO = lift . liftIO
+  {-# INLINE liftIO #-}
+
+instance MonadTrans AnyContT where
+  lift ma = AnyContT (lift ma)
+  {-# INLINE lift #-}
+
+instance MonadThrow m => MonadThrow (AnyContT m) where
+  throwM = lift . throwM
+  {-# INLINE throwM #-}
+
+runAnyContT :: AnyContT m a -> forall r . (a -> m r) -> m r
+runAnyContT k = runContT (unAnyContT k)
+{-# INLINE runAnyContT #-}
+
+runAnyContT' :: (a -> m r) -> AnyContT m a -> m r
+runAnyContT' f k = runContT (unAnyContT k) f
+{-# INLINE runAnyContT' #-}
+
+anyContT :: (forall r . (a -> m r) -> m r) -> AnyContT m a
+anyContT f = AnyContT (ContT f)
+{-# INLINE anyContT #-}
+
+withAnyContT :: (forall r . (b -> m r) -> (a -> m r)) -> AnyContT m a -> AnyContT m b
+withAnyContT f m = anyContT $ runAnyContT m . f
+{-# INLINE withAnyContT #-}
+
+mapAnyContT :: (forall r . m r -> m r) -> AnyContT m a -> AnyContT m a
+mapAnyContT f m = anyContT $ f . runAnyContT m
+{-# INLINE mapAnyContT #-}
diff --git a/src/LLVM.hs b/src/LLVM.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM.hs
@@ -0,0 +1,116 @@
+{-|
+Module : LLVM
+Description: An interface to use LLVM in all capacities.
+Copyright: (c) Moritz Kiefer 2018
+               Stephen Diehl 2018
+               Benjamin Scarlett 2016
+Maintainer: moritz.kiefer@purelyfunctional.org
+-}
+module LLVM (
+  module LLVM.Module
+  -- * Overview of the @llvm-hs@ library ecosystem
+  -- $ecosystem
+
+  -- * Constructing the C++ representation of an LLVM module
+  -- $moduleconstruction
+
+  -- * #objectcode# Generating object code
+  -- $objectcode
+
+  -- * #jitcompilation# JIT compilation
+  -- $jitcompilation
+  ) where
+
+import LLVM.Module
+
+import LLVM.AST ()
+
+{- $ecosystem
+
+The main two libraries in the @llvm-hs@ ecosystem are @llvm-hs-pure@
+and @llvm-hs@.
+
+* @llvm-hs-pure@ defines a pure Haskell representation of the LLVM
+AST. It has no dependency on the LLVM C/C++ libraries so even if you
+have trouble installing those or want to avoid that dependency, you
+should be able to use it. The documentation
+in [LLVM.AST](https://hackage.haskell.org/package/llvm-hs-pure/docs/LLVM-AST.html)
+describes the different options for constructing the AST.
+
+* @llvm-hs@ then builds upon @llvm-hs-pure@ and provides the actual FFI
+bindings to LLVM’s C++ libraries. Most importantly this includes
+bidirectional conversions from the Haskell representation of an LLVM
+module to the C++ representation and the other way around.
+
+Once you have constructed the C++ representation, there are two main options:
+
+1. Generate object code as described in "LLVM#objectcode"
+2. or JIT compile the module as described in "LLVM#jitcompilation".
+
+In addition to @llvm-hs@ and @llvm-hs-pure@, there are a couple of
+other libraries that you be interested in:
+
+* [llvm-hs-pretty](https://hackage.haskell.org/package/llvm-hs-pretty)
+  a pure Haskell prettyprinter for the AST in @llvm-hs-pure@. This is
+  useful if you just want to render your AST to LLVM’s textual IR
+  format either for debugging purposes (@llc@ will usually give pretty
+  good error messages for invalid IR) or because you prefer to call
+  the LLVM CLI tools over the linking against the LLVM libraries.
+
+* [llvm-hs-typed](https://github.com/llvm-hs/llvm-hs-typed) contains a
+  strongly-typed wrapper for the AST in @llvm-hs-pure@ which makes it
+  harder to accidentally construct invalid LLVM IR.
+
+* [llvm-hs-quote](https://github.com/llvm-hs/llvm-hs-quote) contains a
+  Haskell quasiquoter that can be used for splicing larger chunks of
+  existing LLVM IR into your Haskell code.
+
+Finally, there is a [translation](https://github.com/llvm-hs/llvm-hs-kaleidoscope) of
+LLVM’s official Kaleidoscope tutorial to @llvm-hs@ and you can find
+small, self-contained examples covering various parts of the API in
+the [llvm-hs-examples](https://github.com/llvm-hs/llvm-hs-examples)
+repository.
+-}
+
+{- $moduleconstruction
+
+Interacting with the LLVM libraries requires that you first construct
+the C++ representation of an LLVM `Module`.
+
+The most common way of doing that is to first construct the Haskell
+representation of an LLVM module using @llvm-hs-pure@. You can then
+use `withModuleFromAST` to convert the Haskell AST to the C++
+representation.
+
+Alternatively, you can also construct a module from LLVM’s textual IR
+or the binary bitcode format using `withModuleFromLLVMAssembly` and
+`withModuleFromBitcode`.
+
+-}
+
+{- $objectcode
+
+Once you have constructed the C++ representation of an LLVM `Module`,
+you can generate an object file using `moduleObject` which will give
+you a `Data.ByteString.ByteString` or write it to a file using
+`writeObjectToFile`. To construct the `TargetMachine` for these
+functions you can use `LLVM.Target.withHostTargetMachine` if you want
+to generate object code for the machine you are currently running on
+or use `LLVM.Target.withTargetMachine` and customize the target
+machine based on your needs.
+-}
+
+{- $jitcompilation
+
+In addition to generating object code, you can also JIT-compile LLVM
+modules and call functions in the resulting `Module` from Haskell.
+
+LLVM has several JIT compilers but ORC JIT is the one that is actively
+being developed and the one best supported by @llvm-hs@.
+
+Since ORC JIT is still in active development in LLVM, the API is likely to
+change regularly. See the
+[Kaleidoscope](https://github.com/llvm-hs/llvm-hs-kaleidoscope) project for the
+most up-to-date example of using ORC JIT.
+
+-}
diff --git a/src/LLVM/AST.hs b/src/LLVM/AST.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | This module and descendants define AST data types to represent LLVM code.
+-- Note that these types are designed for fidelity rather than convenience - if the truth
+-- of what LLVM supports is less than pretty, so be it.
+module LLVM.AST (
+  Module(..), defaultModule,
+  Definition(..),
+  Global(GlobalVariable, GlobalAlias, Function),
+        globalVariableDefaults,
+        globalAliasDefaults,
+        functionDefaults,
+  UnnamedAddr(..),
+  Parameter(..),
+  BasicBlock(..),
+  Operand(..),
+  CallableOperand,
+  Metadata(..),
+  MetadataNodeID(..),
+  MDRef(..),
+  MDNode(..),
+  module LLVM.AST.Instruction,
+  module LLVM.AST.Name,
+  module LLVM.AST.Type
+  -- * Overview
+  -- $overview
+
+  -- * Constructing the AST for an LLVM module
+  -- $moduleconstruction
+  ) where
+
+import LLVM.Prelude
+
+import LLVM.AST.Name
+import LLVM.AST.Type (Type(..), FloatingPointType(..))
+import LLVM.AST.Global
+import LLVM.AST.Operand hiding (Module)
+import LLVM.AST.Instruction
+import LLVM.AST.DataLayout
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.COMDAT as COMDAT
+
+{- $overview
+
+@llvm-hs-pure@ defines the Haskell AST for representing an LLVM
+`Module`. For interacting with the LLVM C/C++ libraries and an
+overview of the various libraries in the @llvm-hs@ ecosystem, take a
+look at the docs in the @LLVM@ module in @llvm-hs@.
+
+In addition to constructing the LLVM AST manually, there is also a
+monadic IRBuilder interface in `LLVM.IRBuilder`. The IRBuilder will
+take care of generating fresh names automatically and generally
+reduces the verbosity of using the AST directly. Using
+@RecursiveDo/mdo@, it is also capable of handling forward references
+automatically.
+-}
+
+-- | Any thing which can be at the top level of a 'Module'
+data Definition
+  = GlobalDefinition Global
+  | TypeDefinition Name (Maybe Type)
+  | MetadataNodeDefinition MetadataNodeID MDNode
+  | NamedMetadataDefinition ShortByteString [MetadataNodeID]
+  | ModuleInlineAssembly ByteString
+  | FunctionAttributes A.GroupID [A.FunctionAttribute]
+  | COMDAT ShortByteString COMDAT.SelectionKind
+    deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#module-structure>
+-- You can for example put this in withModuleFromAst
+-- <https://hackage.haskell.org/package/llvm-party/docs/LLVM-Module.html#v:withModuleFromAST>
+data Module =
+  Module {
+    moduleName :: ShortByteString,
+    moduleSourceFileName :: ShortByteString,
+    -- | a 'DataLayout', if specified, must match that of the eventual code generator
+    moduleDataLayout :: Maybe DataLayout,
+    moduleTargetTriple :: Maybe ShortByteString,
+    moduleDefinitions :: [Definition]
+  }
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | helper for making 'Module's
+defaultModule :: Module
+defaultModule =
+  Module {
+    moduleName = "<string>",
+    moduleSourceFileName = "<string>",
+    moduleDataLayout = Nothing,
+    moduleTargetTriple = Nothing,
+    moduleDefinitions = []
+  }
diff --git a/src/LLVM/AST/AddrSpace.hs b/src/LLVM/AST/AddrSpace.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/AddrSpace.hs
@@ -0,0 +1,8 @@
+-- | Pointers exist in Address Spaces 
+module LLVM.AST.AddrSpace where
+
+import LLVM.Prelude
+
+-- | See <http://llvm.org/docs/LangRef.html#pointer-type>
+data AddrSpace = AddrSpace Word32
+   deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/Attribute.hs b/src/LLVM/AST/Attribute.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Attribute.hs
@@ -0,0 +1,19 @@
+-- | Module to allow importing 'Attribute' distinctly qualified.
+-- Before LLVM 3.5, the attributes which could be used on functions
+-- and those which could be used on parameters were disjoint.  In
+-- LLVM 3.5, two attributes (readonly and readnone) can be used
+-- in both contexts. Because their interpretation is different in
+-- the two contexts and only those two attributes can be used in
+-- both contexts, I've opted to keep the Haskell types for parameter
+-- and function attributes distinct, but move the two types into
+-- separate modules so they can have contructors with the same names.
+module LLVM.AST.Attribute (
+    ParameterAttribute(..),
+    FunctionAttribute(..),
+    GroupID(..)
+  ) where
+
+import LLVM.AST.ParameterAttribute
+       hiding (NoFree, ReadNone, ReadOnly, StringAttribute, WriteOnly,
+               stringAttributeKind, stringAttributeValue)
+import LLVM.AST.FunctionAttribute
diff --git a/src/LLVM/AST/COMDAT.hs b/src/LLVM/AST/COMDAT.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/COMDAT.hs
@@ -0,0 +1,13 @@
+-- | Module to allow importing 'COMDAT.SelectionKind' distinctly qualified.
+module LLVM.AST.COMDAT where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#comdats>
+data SelectionKind
+  = Any
+  | ExactMatch
+  | Largest
+  | NoDuplicates
+  | SameSize
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/CallingConvention.hs b/src/LLVM/AST/CallingConvention.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/CallingConvention.hs
@@ -0,0 +1,50 @@
+-- | Module to allow importing 'CallingConvention' distinctly qualified.
+module LLVM.AST.CallingConvention where
+
+import LLVM.Prelude
+
+-- |  <http://llvm.org/docs/LangRef.html#callingconv>
+data CallingConvention
+  = C
+  | Fast
+  | Cold
+  | GHC
+  | HiPE
+  | WebKit_JS
+  | AnyReg
+  | PreserveMost
+  | PreserveAll
+  | Swift
+  | CXX_FastTLS
+  | X86_StdCall
+  | X86_FastCall
+  | ARM_APCS
+  | ARM_AAPCS
+  | ARM_AAPCS_VFP
+  | MSP430_INTR
+  | X86_ThisCall
+  | PTX_Kernel
+  | PTX_Device
+  | SPIR_FUNC
+  | SPIR_KERNEL
+  | Intel_OCL_BI
+  | X86_64_SysV
+  | Win64
+  | X86_VectorCall
+  | HHVM
+  | HHVM_C
+  | X86_Intr
+  | AVR_Intr
+  | AVR_Signal
+  | AVR_Builtin
+  | AMDGPU_VS
+  | AMDGPU_HS
+  | AMDGPU_GS
+  | AMDGPU_PS
+  | AMDGPU_CS
+  | AMDGPU_Kernel
+  | X86_RegCall
+  | MSP430_Builtin
+  | Numbered Word32
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
diff --git a/src/LLVM/AST/Constant.hs b/src/LLVM/AST/Constant.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Constant.hs
@@ -0,0 +1,247 @@
+-- | A representation of LLVM constants
+module LLVM.AST.Constant where
+
+import LLVM.Prelude
+
+import Data.Bits ((.|.), (.&.), complement, testBit, shiftL)
+
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.FloatingPointPredicate (FloatingPointPredicate)
+import LLVM.AST.IntegerPredicate (IntegerPredicate)
+import LLVM.AST.AddrSpace ( AddrSpace(..) )
+import qualified LLVM.AST.Float as F
+
+{- |
+<http://llvm.org/docs/LangRef.html#constants>
+
+N.B. - <http://llvm.org/docs/LangRef.html#constant-expressions>
+
+Although constant expressions and instructions have many similarites, there are important
+differences - so they're represented using different types in this AST. At the cost of making it
+harder to move an code back and forth between being constant and not, this approach embeds more of
+the rules of what IR is legal into the Haskell types.
+-}
+data Constant
+    = Int { integerBits :: Word32, integerValue :: Integer }
+    | Float { floatValue :: F.SomeFloat }
+    | Null { constantType :: Type }
+    | AggregateZero { constantType :: Type }
+    | Struct { structName :: Maybe Name, isPacked :: Bool, memberValues :: [ Constant ] }
+    | Array { memberType :: Type, memberValues :: [ Constant ] }
+    | Vector { memberValues :: [ Constant ] }
+    | Undef { constantType :: Type }
+    | BlockAddress { blockAddressFunction :: Name, blockAddressBlock :: Name }
+    | GlobalReference Type Name
+    | TokenNone
+    | Add {
+        nsw :: Bool,
+        nuw :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FAdd {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Sub {
+        nsw :: Bool,
+        nuw :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FSub {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Mul {
+        nsw :: Bool,
+        nuw :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FMul {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | UDiv {
+        exact :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | SDiv {
+        exact :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FDiv {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | URem {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | SRem {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FRem {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Shl {
+        nsw :: Bool,
+        nuw :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | LShr {
+        exact :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | AShr {
+        exact :: Bool,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | And {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Or {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Xor {
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | GetElementPtr {
+        inBounds :: Bool,
+        address :: Constant,
+        indices :: [Constant]
+      }
+    | Trunc {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | ZExt {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | SExt {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | FPToUI {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | FPToSI {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | UIToFP {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | SIToFP {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | FPTrunc {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | FPExt {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | PtrToInt {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | IntToPtr {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | BitCast {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | AddrSpaceCast {
+        operand0 :: Constant,
+        type' :: Type
+      }
+    | ICmp {
+        iPredicate :: IntegerPredicate,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | FCmp {
+        fpPredicate :: FloatingPointPredicate,
+        operand0 :: Constant,
+        operand1 :: Constant
+      }
+    | Select {
+        condition' :: Constant,
+        trueValue :: Constant,
+        falseValue :: Constant
+      }
+    | ExtractElement {
+        vector :: Constant,
+        index :: Constant
+      }
+    | InsertElement {
+        vector :: Constant,
+        element :: Constant,
+        index :: Constant
+      }
+    | ShuffleVector {
+        operand0 :: Constant,
+        operand1 :: Constant,
+        mask :: Constant
+      }
+    | ExtractValue {
+        aggregate :: Constant,
+        indices' :: [Word32]
+      }
+    | InsertValue {
+        aggregate :: Constant,
+        element :: Constant,
+        indices' :: [Word32]
+      }
+    deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+
+-- | Since LLVM types don't include signedness, there's ambiguity in interpreting
+-- an constant as an Integer. The LLVM assembly printer prints integers as signed, but
+-- cheats for 1-bit integers and prints them as 'true' or 'false'. That way it circuments the
+-- otherwise awkward fact that a twos complement 1-bit number only has the values -1 and 0.
+signedIntegerValue :: Constant -> Integer
+signedIntegerValue (Int nBits' bits) =
+  let nBits = fromIntegral nBits'
+  in
+    if bits `testBit` (nBits - 1) then bits .|. (-1 `shiftL` nBits) else bits
+signedIntegerValue _ = error "signedIntegerValue is only defined for Int"
+
+-- | This library's conversion from LLVM C++ objects will always produce integer constants
+-- as unsigned, so this function in many cases is not necessary. However, nothing's to keep
+-- stop direct construction of an 'Int' with a negative 'integerValue'. There's nothing in principle
+-- wrong with such a value - it has perfectly good low order bits like any integer, and will be used
+-- as such, likely producing the intended result if lowered to C++. If, however one wishes to interpret
+-- an 'Int' of unknown provenance as unsigned, then this function will serve.
+unsignedIntegerValue :: Constant -> Integer
+unsignedIntegerValue (Int nBits bits) =
+  bits .&. (complement (-1 `shiftL` (fromIntegral nBits)))
+unsignedIntegerValue _ = error "unsignedIntegerValue is only defined for Int"
+
+-- platform independant sizeof: a gep to the end of a nullptr and some bitcasting.
+sizeof :: Word32 -> Type -> Constant
+sizeof szBits t = PtrToInt szPtr (IntegerType szBits)
+  where
+     ptrType = PointerType t (AddrSpace 0)
+     nullPtr = IntToPtr (Int szBits 0) ptrType
+     szPtr   = GetElementPtr True nullPtr [Int szBits 1]
diff --git a/src/LLVM/AST/DLL.hs b/src/LLVM/AST/DLL.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/DLL.hs
@@ -0,0 +1,10 @@
+-- | Module to allow importing 'DLL.StorageClass' distinctly qualified.
+module LLVM.AST.DLL where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#dll-storage-classes>
+data StorageClass
+    = Import
+    | Export
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/DataLayout.hs b/src/LLVM/AST/DataLayout.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/DataLayout.hs
@@ -0,0 +1,76 @@
+-- | <http://llvm.org/docs/LangRef.html#data-layout>
+module LLVM.AST.DataLayout where
+
+import LLVM.Prelude
+
+import Data.Map (Map)
+import qualified Data.Map as Map
+import Data.Set (Set)
+
+import LLVM.AST.AddrSpace
+
+-- | Little Endian is the one true way :-). Sadly, we must support the infidels.
+data Endianness = LittleEndian | BigEndian
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | An AlignmentInfo describes how a given type must and would best be aligned
+data AlignmentInfo = AlignmentInfo {
+    abiAlignment :: Word32,
+    preferredAlignment :: Word32
+  }
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | A type of type for which 'AlignmentInfo' may be specified
+data AlignType
+  = IntegerAlign
+  | VectorAlign
+  | FloatAlign
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | A style of name mangling
+data Mangling
+  = ELFMangling
+  | MIPSMangling
+  | MachOMangling
+  | WindowsCOFFMangling
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | a description of the various data layout properties which may be used during
+-- optimization
+data DataLayout = DataLayout {
+    endianness :: Endianness,
+    mangling :: Maybe Mangling,
+    stackAlignment :: Maybe Word32,
+    pointerLayouts :: Map AddrSpace (Word32, AlignmentInfo),
+    typeLayouts :: Map (AlignType, Word32) AlignmentInfo,
+    aggregateLayout :: AlignmentInfo,
+    nativeSizes :: Maybe (Set Word32)
+  }
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | a default 'DataLayout'
+defaultDataLayout :: Endianness -> DataLayout
+defaultDataLayout defaultEndianness = DataLayout {
+  endianness = defaultEndianness,
+  mangling = Nothing,
+  stackAlignment = Nothing,
+  pointerLayouts = Map.fromList [
+    (AddrSpace 0, (64, AlignmentInfo 64 64))
+   ],
+  typeLayouts = Map.fromList [
+    ((IntegerAlign, 1), AlignmentInfo 8 8),
+    ((IntegerAlign, 8), AlignmentInfo 8 8),
+    ((IntegerAlign, 16), AlignmentInfo 16 16),
+    ((IntegerAlign, 32), AlignmentInfo 32 32),
+    ((IntegerAlign, 64), AlignmentInfo 32 64),
+    ((FloatAlign, 16), AlignmentInfo 16 16),
+    ((FloatAlign, 32), AlignmentInfo 32 32),
+    ((FloatAlign, 64), AlignmentInfo 64 64),
+    ((FloatAlign, 128), AlignmentInfo 128 128),
+    ((VectorAlign, 64), AlignmentInfo 64 64),
+    ((VectorAlign, 128), AlignmentInfo 128 128)
+   ],
+  aggregateLayout = AlignmentInfo 0 64,
+  nativeSizes = Nothing
+ }
+
diff --git a/src/LLVM/AST/Float.hs b/src/LLVM/AST/Float.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Float.hs
@@ -0,0 +1,18 @@
+-- | This module provides a sub-namespace for a type to support the various sizes of floating point
+-- numbers LLVM supports. It is most definitely intended to be imported qualified.
+module LLVM.AST.Float where
+
+import LLVM.Prelude
+
+-- | A type summing up the various float types.
+-- N.B. Note that in the constructors with multiple fields, the lower significance bits are on the right
+-- - e.g. Quadruple highbits lowbits
+data SomeFloat
+  = Half Word16
+  | Single Float
+  | Double Double
+  | Quadruple Word64 Word64
+  | X86_FP80 Word16 Word64
+  | PPC_FP128 Word64 Word64
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
diff --git a/src/LLVM/AST/FloatingPointPredicate.hs b/src/LLVM/AST/FloatingPointPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/FloatingPointPredicate.hs
@@ -0,0 +1,27 @@
+-- | Predicates for the 'LLVM.AST.Instruction.FCmp' instruction
+module LLVM.AST.FloatingPointPredicate where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#fcmp-instruction>
+data FloatingPointPredicate
+  = False
+  | OEQ
+  | OGT
+  | OGE
+  | OLT
+  | OLE
+  | ONE
+  | ORD
+  | UNO
+  | UEQ
+  | UGT
+  | UGE
+  | ULT
+  | ULE
+  | UNE
+  | True
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
+
+
diff --git a/src/LLVM/AST/FunctionAttribute.hs b/src/LLVM/AST/FunctionAttribute.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/FunctionAttribute.hs
@@ -0,0 +1,59 @@
+-- | Module to allow importing 'FunctionAttribute' distinctly qualified.
+module LLVM.AST.FunctionAttribute where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#function-attributes>
+data FunctionAttribute
+    = AllocSize Word32 (Maybe Word32) -- ^ AllocSize 0 (Just 0) is invalid
+    | AlwaysInline
+    | ArgMemOnly
+    | Builtin
+    | Cold
+    | Convergent
+    | InaccessibleMemOnly
+    | InaccessibleMemOrArgMemOnly
+    | InlineHint
+    | JumpTable
+    | MinimizeSize
+    | MustProgress
+    | Naked
+    | NoBuiltin
+    | NoDuplicate
+    | NoFree
+    | NoImplicitFloat
+    | NoInline
+    | NonLazyBind
+    | NoRecurse
+    | NoRedZone
+    | NoReturn
+    | NoSync
+    | NoUnwind
+    | OptimizeForSize
+    | OptimizeNone
+    | ReadNone
+    | ReadOnly
+    | ReturnsTwice
+    | SafeStack
+    | SanitizeAddress
+    | SanitizeHWAddress
+    | SanitizeMemory
+    | SanitizeThread
+    | Speculatable
+    | StackAlignment Word64
+    | StackProtect
+    | StackProtectReq
+    | StackProtectStrong
+    | StrictFP
+    | StringAttribute {
+        stringAttributeKind :: ShortByteString,
+        stringAttributeValue :: ShortByteString -- ^ Use "" for no value -- the two are conflated
+      }
+    | UWTable
+    | WillReturn
+    | WriteOnly
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#attribute-groups>
+newtype GroupID = GroupID Word
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/Global.hs b/src/LLVM/AST/Global.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Global.hs
@@ -0,0 +1,141 @@
+-- | 'Global's - top-level values in 'Module's - and supporting structures.
+module LLVM.AST.Global where
+
+import LLVM.Prelude
+
+import LLVM.AST.Name
+import LLVM.AST.Type
+import LLVM.AST.Constant (Constant)
+import LLVM.AST.AddrSpace
+import LLVM.AST.Instruction (Named, Instruction, Terminator)
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.DLL as DLL
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.ThreadLocalStorage as TLS
+import qualified LLVM.AST.Attribute as A
+import LLVM.AST.Operand (MDRef, MDNode)
+
+-- | <http://llvm.org/doxygen/classllvm_1_1GlobalValue.html>
+data Global
+    -- | <http://llvm.org/docs/LangRef.html#global-variables>
+    = GlobalVariable {
+        name :: Name,
+        linkage :: L.Linkage,
+        visibility :: V.Visibility,
+        dllStorageClass :: Maybe DLL.StorageClass,
+        threadLocalMode :: Maybe TLS.Model,
+        unnamedAddr :: Maybe UnnamedAddr,
+        isConstant :: Bool,
+        type' :: Type,
+        addrSpace :: AddrSpace,
+        initializer :: Maybe Constant,
+        section :: Maybe ShortByteString,
+        comdat :: Maybe ShortByteString,
+        alignment :: Word32,
+        metadata :: [(ShortByteString, MDRef MDNode)]
+      }
+    -- | <http://llvm.org/docs/LangRef.html#aliases>
+    | GlobalAlias {
+        name :: Name,
+        linkage :: L.Linkage,
+        visibility :: V.Visibility,
+        dllStorageClass :: Maybe DLL.StorageClass,
+        threadLocalMode :: Maybe TLS.Model,
+        unnamedAddr :: Maybe UnnamedAddr,
+        type' :: Type,
+        addrSpace :: AddrSpace,
+        aliasee :: Constant
+      }
+    -- | <http://llvm.org/docs/LangRef.html#functions>
+    | Function {
+        linkage :: L.Linkage,
+        visibility :: V.Visibility,
+        dllStorageClass :: Maybe DLL.StorageClass,
+        callingConvention :: CC.CallingConvention,
+        returnAttributes :: [A.ParameterAttribute],
+        returnType :: Type,
+        name :: Name,
+        parameters :: ([Parameter],Bool), -- ^ snd indicates varargs
+        functionAttributes :: [Either A.GroupID A.FunctionAttribute],
+        section :: Maybe ShortByteString,
+        comdat :: Maybe ShortByteString,
+        alignment :: Word32,
+        garbageCollectorName :: Maybe ShortByteString,
+        prefix :: Maybe Constant,
+        basicBlocks :: [BasicBlock],
+        personalityFunction :: Maybe Constant,
+        metadata :: [(ShortByteString, MDRef MDNode)]
+      }
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | 'Parameter's for 'Function's
+data Parameter = Parameter Type Name [A.ParameterAttribute]
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/classllvm_1_1BasicBlock.html>
+-- LLVM code in a function is a sequence of 'BasicBlock's each with a label,
+-- some instructions, and a terminator.
+data BasicBlock = BasicBlock Name [Named Instruction] (Named Terminator)
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+data UnnamedAddr = LocalAddr | GlobalAddr
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | helper for making 'GlobalVariable's
+globalVariableDefaults :: Global
+globalVariableDefaults = 
+  GlobalVariable {
+  name = error "global variable name not defined",
+  linkage = L.External,
+  visibility = V.Default,
+  dllStorageClass = Nothing,
+  threadLocalMode = Nothing,
+  addrSpace = AddrSpace 0,
+  unnamedAddr = Nothing,
+  isConstant = False,
+  type' = error "global variable type not defined",
+  initializer = Nothing,
+  section = Nothing,
+  comdat = Nothing,
+  alignment = 0,
+  metadata = []
+  }
+
+-- | helper for making 'GlobalAlias's
+globalAliasDefaults :: Global
+globalAliasDefaults =
+  GlobalAlias {
+    name = error "global alias name not defined",
+    linkage = L.External,
+    visibility = V.Default,
+    dllStorageClass = Nothing,
+    threadLocalMode = Nothing,
+    unnamedAddr = Nothing,
+    type' = error "global alias type not defined",
+    addrSpace = AddrSpace 0,
+    aliasee = error "global alias aliasee not defined"
+  }
+
+-- | helper for making 'Function's
+functionDefaults :: Global
+functionDefaults = 
+  Function {
+    linkage = L.External,
+    visibility = V.Default,
+    dllStorageClass = Nothing,
+    callingConvention = CC.C,
+    returnAttributes = [],
+    returnType = error "function return type not defined",
+    name = error "function name not defined",
+    parameters = ([], False),
+    functionAttributes = [],
+    section = Nothing,
+    comdat = Nothing,
+    alignment = 0,
+    garbageCollectorName = Nothing,
+    prefix = Nothing,
+    basicBlocks = [],
+    personalityFunction = Nothing,
+    metadata = []
+  }
diff --git a/src/LLVM/AST/InlineAssembly.hs b/src/LLVM/AST/InlineAssembly.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/InlineAssembly.hs
@@ -0,0 +1,27 @@
+-- | A representation of an LLVM inline assembly
+module LLVM.AST.InlineAssembly where
+
+import LLVM.Prelude
+
+import LLVM.AST.Type
+
+-- | the dialect of assembly used in an inline assembly string
+-- <http://en.wikipedia.org/wiki/X86_assembly_language#Syntax>
+data Dialect
+  = ATTDialect
+  | IntelDialect
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#inline-assembler-expressions>
+-- to be used through 'LLVM.AST.Operand.CallableOperand' with a
+-- 'LLVM.AST.Instruction.Call' instruction
+data InlineAssembly
+  = InlineAssembly {
+      type' :: Type,
+      assembly :: ByteString,
+      constraints :: ShortByteString,
+      hasSideEffects :: Bool,
+      alignStack :: Bool,
+      dialect :: Dialect
+    }
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/Instruction.hs b/src/LLVM/AST/Instruction.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Instruction.hs
@@ -0,0 +1,468 @@
+-- | LLVM instructions
+-- <http://llvm.org/docs/LangRef.html#instruction-reference>
+module LLVM.AST.Instruction where
+
+import LLVM.Prelude
+
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.Constant
+import LLVM.AST.Operand
+import LLVM.AST.IntegerPredicate (IntegerPredicate)
+import LLVM.AST.FloatingPointPredicate (FloatingPointPredicate)
+import LLVM.AST.RMWOperation (RMWOperation)
+import LLVM.AST.CallingConvention (CallingConvention)
+import qualified LLVM.AST.ParameterAttribute as PA (ParameterAttribute)
+import qualified LLVM.AST.FunctionAttribute as FA (FunctionAttribute, GroupID)
+
+import Data.List.NonEmpty
+
+-- | <http://llvm.org/docs/LangRef.html#metadata-nodes-and-metadata-strings>
+-- Metadata can be attached to an instruction
+type InstructionMetadata = [(ShortByteString, MDRef MDNode)]
+
+-- | <http://llvm.org/docs/LangRef.html#terminators>
+data Terminator
+  = Ret {
+      returnOperand :: Maybe Operand,
+      metadata' :: InstructionMetadata
+    }
+  | CondBr {
+      condition :: Operand,
+      trueDest :: Name,
+      falseDest :: Name,
+      metadata' :: InstructionMetadata
+    }
+  | Br {
+      dest :: Name,
+      metadata' :: InstructionMetadata
+    }
+  | Switch {
+      operand0' :: Operand,
+      defaultDest :: Name,
+      dests :: [(Constant, Name)],
+      metadata' :: InstructionMetadata
+    }
+  | IndirectBr {
+      operand0' :: Operand,
+      possibleDests :: [Name],
+      metadata' :: InstructionMetadata
+    }
+  | Invoke {
+      callingConvention' :: CallingConvention,
+      returnAttributes' :: [PA.ParameterAttribute],
+      function' :: CallableOperand,
+      arguments' :: [(Operand, [PA.ParameterAttribute])],
+      functionAttributes' :: [Either FA.GroupID FA.FunctionAttribute],
+      returnDest :: Name,
+      exceptionDest :: Name,
+      metadata' :: InstructionMetadata
+    }
+  | Resume {
+      operand0' :: Operand,
+      metadata' :: InstructionMetadata
+    }
+  | Unreachable {
+      metadata' :: InstructionMetadata
+    }
+  | CleanupRet {
+      cleanupPad :: Operand,
+      unwindDest :: Maybe Name,
+      metadata' :: InstructionMetadata
+    }
+  | CatchRet {
+      catchPad :: Operand,
+      successor :: Name,
+      metadata' :: InstructionMetadata
+    }
+  | CatchSwitch {
+      parentPad' :: Operand,
+      catchHandlers :: NonEmpty Name,
+      defaultUnwindDest :: Maybe Name,
+      metadata' :: InstructionMetadata
+    }
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#fast-math-flags>
+data FastMathFlags
+  = FastMathFlags {
+      allowReassoc :: Bool,
+      noNaNs :: Bool,
+      noInfs :: Bool,
+      noSignedZeros :: Bool,
+      allowReciprocal :: Bool,
+      allowContract :: Bool,
+      approxFunc :: Bool
+    }
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
+noFastMathFlags :: FastMathFlags
+noFastMathFlags =
+  FastMathFlags {
+    allowReassoc = False,
+    noNaNs = False,
+    noInfs = False,
+    noSignedZeros = False,
+    allowReciprocal = False,
+    allowContract = False,
+    approxFunc = False
+  }
+
+-- | <http://llvm.org/docs/LangRef.html#atomic-memory-ordering-constraints>
+-- <http://llvm.org/docs/Atomics.html>
+data MemoryOrdering
+  = Unordered
+  | Monotonic
+  | Acquire
+  | Release
+  | AcquireRelease
+  | SequentiallyConsistent
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#singlethread>
+data SynchronizationScope
+  = SingleThread
+  | System
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
+-- | An 'Atomicity' describes constraints on the visibility of effects of an atomic instruction
+type Atomicity = (SynchronizationScope, MemoryOrdering)
+
+-- | For the redoubtably complex 'LandingPad' instruction
+data LandingPadClause
+    = Catch Constant
+    | Filter Constant
+    deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | For the call instruction
+-- <http://llvm.org/docs/LangRef.html#call-instruction>
+data TailCallKind = Tail | MustTail | NoTail
+    deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | non-terminator instructions:
+-- <http://llvm.org/docs/LangRef.html#unaryops>
+-- <http://llvm.org/docs/LangRef.html#binaryops>
+-- <http://llvm.org/docs/LangRef.html#bitwiseops>
+-- <http://llvm.org/docs/LangRef.html#memoryops>
+-- <http://llvm.org/docs/LangRef.html#otherops>
+data Instruction
+  = FNeg {
+    fastMathFlags :: FastMathFlags,
+    operand0 :: Operand,
+    metadata :: InstructionMetadata
+    }
+  | Add {
+      nsw :: Bool,
+      nuw :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FAdd {
+      fastMathFlags :: FastMathFlags,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Sub {
+      nsw :: Bool,
+      nuw :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FSub {
+      fastMathFlags :: FastMathFlags,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Mul {
+      nsw :: Bool,
+      nuw :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FMul {
+      fastMathFlags :: FastMathFlags,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | UDiv {
+      exact :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | SDiv {
+      exact :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FDiv {
+      fastMathFlags :: FastMathFlags,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | URem {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | SRem {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FRem {
+      fastMathFlags :: FastMathFlags,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Shl {
+      nsw :: Bool,
+      nuw :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | LShr {
+      exact :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | AShr {
+      exact :: Bool,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | And {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Or {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Xor {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Alloca {
+      allocatedType :: Type,
+      numElements :: Maybe Operand,
+      alignment :: Word32,
+      metadata :: InstructionMetadata
+    }
+  | Load {
+      volatile :: Bool,
+      address :: Operand,
+      maybeAtomicity :: Maybe Atomicity,
+      alignment :: Word32,
+      metadata :: InstructionMetadata
+    }
+  | Store {
+      volatile :: Bool,
+      address :: Operand,
+      value :: Operand,
+      maybeAtomicity :: Maybe Atomicity,
+      alignment :: Word32,
+      metadata :: InstructionMetadata
+    }
+  | GetElementPtr {
+      inBounds :: Bool,
+      address :: Operand,
+      indices :: [Operand],
+      metadata :: InstructionMetadata
+    }
+  | Fence {
+      atomicity :: Atomicity,
+      metadata :: InstructionMetadata
+    }
+  | CmpXchg {
+      volatile :: Bool,
+      address :: Operand,
+      expected :: Operand,
+      replacement :: Operand,
+      atomicity :: Atomicity,
+      failureMemoryOrdering :: MemoryOrdering,
+      metadata :: InstructionMetadata
+    }
+  | AtomicRMW {
+      volatile :: Bool,
+      rmwOperation :: RMWOperation,
+      address :: Operand,
+      value :: Operand,
+      atomicity :: Atomicity,
+      metadata :: InstructionMetadata
+    }
+  | Trunc {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | ZExt {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | SExt {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | FPToUI {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | FPToSI {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | UIToFP {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | SIToFP {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | FPTrunc {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | FPExt {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | PtrToInt {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | IntToPtr {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | BitCast {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | AddrSpaceCast {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | ICmp {
+      iPredicate :: IntegerPredicate,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | FCmp {
+      fpPredicate :: FloatingPointPredicate,
+      operand0 :: Operand,
+      operand1 :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Phi {
+      type' :: Type,
+      incomingValues :: [ (Operand, Name) ],
+      metadata :: InstructionMetadata
+  }
+  | Freeze {
+      operand0 :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | Select {
+      condition' :: Operand,
+      trueValue :: Operand,
+      falseValue :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | Call {
+      tailCallKind :: Maybe TailCallKind,
+      callingConvention :: CallingConvention,
+      returnAttributes :: [PA.ParameterAttribute],
+      function :: CallableOperand,
+      arguments :: [(Operand, [PA.ParameterAttribute])],
+      functionAttributes :: [Either FA.GroupID FA.FunctionAttribute],
+      metadata :: InstructionMetadata
+  }
+  | VAArg {
+      argList :: Operand,
+      type' :: Type,
+      metadata :: InstructionMetadata
+    }
+  | ExtractElement {
+      vector :: Operand,
+      index :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | InsertElement {
+      vector :: Operand,
+      element :: Operand,
+      index :: Operand,
+      metadata :: InstructionMetadata
+    }
+  | ShuffleVector {
+      operand0 :: Operand,
+      operand1 :: Operand,
+      mask :: [Int32],
+      metadata :: InstructionMetadata
+    }
+  | ExtractValue {
+      aggregate :: Operand,
+      indices' :: [Word32],
+      metadata :: InstructionMetadata
+    }
+  | InsertValue {
+      aggregate :: Operand,
+      element :: Operand,
+      indices' :: [Word32],
+      metadata :: InstructionMetadata
+    }
+  | LandingPad {
+      type' :: Type,
+      cleanup :: Bool,
+      clauses :: [LandingPadClause],
+      metadata :: InstructionMetadata
+    }
+  | CatchPad {
+      catchSwitch :: Operand,
+      args :: [Operand],
+      metadata :: InstructionMetadata
+    }
+  | CleanupPad {
+      parentPad :: Operand,
+      args :: [Operand],
+      metadata :: InstructionMetadata
+    }
+
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+
+-- | Instances of instructions may be given a name, allowing their results to be referenced as 'Operand's.
+-- Sometimes instructions - e.g. a call to a function returning void - don't need names.
+data Named a
+  = Name := a
+  | Do a
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/IntegerPredicate.hs b/src/LLVM/AST/IntegerPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/IntegerPredicate.hs
@@ -0,0 +1,21 @@
+-- | Predicates for the 'LLVM.AST.Instruction.ICmp' instruction
+module LLVM.AST.IntegerPredicate where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#icmp-instruction>
+data IntegerPredicate
+  = EQ
+  | NE
+  | UGT
+  | UGE
+  | ULT
+  | ULE
+  | SGT
+  | SGE
+  | SLT
+  | SLE
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
+
+
diff --git a/src/LLVM/AST/Linkage.hs b/src/LLVM/AST/Linkage.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Linkage.hs
@@ -0,0 +1,19 @@
+-- | Module to allow importing 'Linkage' distinctly qualified.
+module LLVM.AST.Linkage where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#linkage>
+data Linkage
+    = Private
+    | Internal
+    | AvailableExternally
+    | LinkOnce
+    | Weak
+    | Common
+    | Appending
+    | ExternWeak
+    | LinkOnceODR
+    | WeakODR
+    | External
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/Name.hs b/src/LLVM/AST/Name.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Name.hs
@@ -0,0 +1,45 @@
+-- | Names as used in LLVM IR
+module LLVM.AST.Name where
+
+import LLVM.Prelude
+import Data.Char
+import Data.String
+
+{- |
+Objects of various sorts in LLVM IR are identified by address in the LLVM C++ API, and
+may be given a string name. When printed to (resp. read from) human-readable LLVM assembly, objects without
+string names are numbered sequentially (resp. must be numbered sequentially). String names may be quoted, and
+are quoted when printed if they would otherwise be misread - e.g. when containing special characters.
+
+> 7
+
+means the seventh unnamed object, while
+
+> "7"
+
+means the object named with the string "7".
+
+This libraries handling of 'UnName's during translation of the AST down into C++ IR is somewhat more
+forgiving than the LLVM assembly parser: it does not require that unnamed values be numbered sequentially;
+however, the numbers of 'UnName's passed into C++ cannot be preserved in the C++ objects. If the C++ IR is
+printed as assembly or translated into a Haskell AST, unnamed nodes will be renumbered sequentially. Thus
+unnamed node numbers should be thought of as having any scope limited to the 'LLVM.AST.Module' in
+which they are used.
+-}
+data Name
+    = Name ShortByteString -- ^ a string name
+    | UnName Word -- ^ a number for a nameless thing
+   deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Using 'fromString` on non-ASCII strings will throw an error.
+instance IsString Name where
+  fromString s
+    | all isAscii s = Name (fromString s)
+    | otherwise =
+      error ("Only ASCII strings are automatically converted to LLVM names. "
+          <> "Other strings need to be encoded to a `ShortByteString` using an arbitrary encoding.")
+
+-- | Create a 'Name' based on an ASCII 'String'.
+-- Non-ASCII strings will throw an error.
+mkName :: String -> Name
+mkName = fromString
diff --git a/src/LLVM/AST/Operand.hs b/src/LLVM/AST/Operand.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Operand.hs
@@ -0,0 +1,554 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+-- | A type to represent operands to LLVM 'LLVM.AST.Instruction.Instruction's
+module LLVM.AST.Operand
+( module LLVM.AST.Operand
+)
+where
+
+import LLVM.Prelude
+
+import LLVM.AST.Name
+import LLVM.AST.Constant
+import LLVM.AST.InlineAssembly
+import LLVM.AST.Type
+
+
+-- | An 'Operand' is roughly that which is an argument to an 'LLVM.AST.Instruction.Instruction'
+data Operand
+  -- | %foo
+  = LocalReference Type Name
+  -- | 'Constant's include 'LLVM.AST.Constant.GlobalReference', for \@foo
+  | ConstantOperand Constant
+  | MetadataOperand Metadata
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | The 'LLVM.AST.Instruction.Call' instruction is special: the callee can be inline assembly
+type CallableOperand  = Either InlineAssembly Operand
+
+-- | <http://llvm.org/docs/LangRef.html#metadata>
+data Metadata
+  = MDString ShortByteString -- ^ <http://llvm.org/docs/doxygen/html/classllvm_1_1MDNode.html>
+  | MDNode (MDRef MDNode) -- ^ <http://llvm.org/docs/doxygen/html/classllvm_1_1MDNode.html>
+  | MDValue Operand -- ^ <http://llvm.org/docs/doxygen/html/classllvm_1_1ValueAsMetadata.html>
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | A 'MetadataNodeID' is a number for identifying a metadata node.
+-- Note this is different from "named metadata", which are represented with
+-- 'LLVM.AST.NamedMetadataDefinition'.
+newtype MetadataNodeID = MetadataNodeID Word
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | `MDRef` can either represent a reference to some piece of
+-- metadata or the metadata itself.
+--
+-- This is mainly useful for encoding cyclic metadata. Note that LLVM
+-- represents inline and non-inline nodes identically, so
+-- roundtripping the Haskell AST does not preserve whether a node was
+-- inline or not.
+data MDRef a
+  = MDRef MetadataNodeID
+  | MDInline a
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+instance Functor MDRef where
+  fmap _ (MDRef i) = MDRef i
+  fmap f (MDInline a) = MDInline (f a)
+
+data DWOpFragment = DW_OP_LLVM_Fragment
+  { offset :: Word64
+  , size :: Word64
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#diexpression>
+data DWOp
+  = DW_OP_And
+  | DW_OP_Bregx
+  | DW_OP_ConstU Word64
+  | DW_OP_Deref
+  | DW_OP_Div
+  | DW_OP_Dup
+  | DwOpFragment DWOpFragment -- ^ Must appear at the end
+  | DW_OP_Lit0
+  | DW_OP_Minus
+  | DW_OP_Mod
+  | DW_OP_Mul
+  | DW_OP_Not
+  | DW_OP_Or
+  | DW_OP_Plus
+  | DW_OP_PlusUConst Word64
+  | DW_OP_PushObjectAddress
+  | DW_OP_Shl
+  | DW_OP_Shr
+  | DW_OP_Shra
+  | DW_OP_StackValue -- ^ Must be the last one or followed by a DW_OP_LLVM_Fragment
+  | DW_OP_Swap
+  | DW_OP_XDeref
+  | DW_OP_Xor
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#metadata>
+data MDNode
+  = MDTuple [Maybe Metadata] -- ^ Nothing represents 'null'
+  | DIExpression DIExpression
+  | DIGlobalVariableExpression DIGlobalVariableExpression
+  | DILocation DILocation
+  | DIMacroNode DIMacroNode
+  | DINode DINode
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DILocation = Location
+  { line :: Word32
+  , column :: Word16
+  , scope :: MDRef DILocalScope
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#diexpression>
+data DIExpression = Expression
+  { operands :: [DWOp]
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | A pair of a `DIGlobalVariable` and a `DIExpression`.
+--
+-- This is used in the `cuGlobals` fields of `DICompileUnit`.
+data DIGlobalVariableExpression = GlobalVariableExpression
+  { var :: MDRef DIGlobalVariable
+  , expr :: MDRef DIExpression
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Accessiblity flag
+data DIAccessibility
+  = Private
+  | Protected
+  | Public
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Inheritance flag
+data DIInheritance
+  = SingleInheritance
+  | MultipleInheritance
+  | VirtualInheritance
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DIFlag
+  = Accessibility DIAccessibility
+  | FwdDecl
+  | AppleBlock
+  | ReservedBit4 -- Used to be BlockByRef, can be reused for anything except DICompositeType.
+  | VirtualFlag
+  | Artificial
+  | Explicit
+  | Prototyped
+  | ObjcClassComplete
+  | ObjectPointer
+  | Vector
+  | StaticMember
+  | LValueReference
+  | RValueReference
+  | InheritanceFlag DIInheritance
+  | IntroducedVirtual
+  | BitField
+  | NoReturn
+  | TypePassByValue
+  | TypePassByReference
+  | EnumClass
+  | Thunk
+  | NonTrivial
+  | BigEndian
+  | LittleEndian
+  | AllCallsDescribed
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DIMacroInfo = Define | Undef
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DIMacroNode.html>
+data DIMacroNode
+  -- | <https://llvm.org/docs/LangRef.html#dimacro>
+  = DIMacro
+    { info :: DIMacroInfo
+    , line :: Word32
+    , name :: ShortByteString
+    , value :: ShortByteString
+    }
+  -- | <https://llvm.org/docs/LangRef.html#dimacrofile>
+  | DIMacroFile
+    { line :: Word32
+    , file :: MDRef DIFile
+    , elements :: [MDRef DIMacroNode]
+    }
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DINode.html>
+data DINode
+  = DIEnumerator DIEnumerator
+  | DIImportedEntity DIImportedEntity
+  | DIObjCProperty DIObjCProperty
+  | DIScope DIScope
+  | DISubrange DISubrange
+  | DITemplateParameter DITemplateParameter
+  | DIVariable DIVariable
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DIObjCProperty.html>
+data DIObjCProperty = ObjCProperty
+  { name :: ShortByteString
+  , file :: Maybe (MDRef DIFile)
+  , line :: Word32
+  , getterName :: ShortByteString
+  , setterName :: ShortByteString
+  , attributes :: Word32
+  , type' :: Maybe (MDRef DIType)
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data ImportedEntityTag = ImportedModule | ImportedDeclaration
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DIImportedEntity.html>
+data DIImportedEntity = ImportedEntity
+  { tag :: ImportedEntityTag
+  , name :: ShortByteString
+  , scope :: MDRef DIScope
+  , entity :: Maybe (MDRef DINode)
+  , file :: Maybe (MDRef DIFile)
+  , line :: Word32
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#dienumerator>
+data DIEnumerator =
+  Enumerator { value :: Int64, isUnsigned :: Bool, name :: ShortByteString }
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#disubrange>
+data DISubrange = Subrange
+  { count :: DICount
+  , lowerBound :: Maybe DIBound
+  , upperBound :: Maybe DIBound
+  , stride :: Maybe DIBound
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DICount
+  = DICountConstant Int64
+  | DICountVariable (MDRef DIVariable)
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DIBound
+  = DIBoundConstant Int64
+  | DIBoundVariable (MDRef DIVariable)
+  | DIBoundExpression (MDRef DIExpression)
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DIScope.html>
+data DIScope
+  = DICompileUnit DICompileUnit
+  | DIFile DIFile
+  | DILocalScope DILocalScope
+  | DIModule DIModule
+  | DINamespace DINamespace
+  | DIType DIType
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DIModule = Module
+  { scope :: Maybe (MDRef DIScope)
+  , name :: ShortByteString
+  , configurationMacros :: ShortByteString
+  , includePath :: ShortByteString
+  , apiNotesFile :: ShortByteString
+  , lineNo :: Word32
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DINamespace = Namespace
+  { name :: ShortByteString
+  , scope :: Maybe (MDRef DIScope)
+  , exportSymbols :: Bool
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DebugEmissionKind = NoDebug | FullDebug | LineTablesOnly
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DebugNameTableKind = NameTableKindDefault | NameTableKindGNU | NameTableKindNone
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#dicompileunit>
+data DICompileUnit = CompileUnit
+  { language :: Word32
+  , file :: MDRef DIFile
+  , producer :: ShortByteString
+  , optimized :: Bool
+  , flags :: ShortByteString
+  , runtimeVersion :: Word32
+  , splitDebugFileName :: ShortByteString
+  , emissionKind :: DebugEmissionKind
+  , enums :: [MDRef DICompositeType] -- ^ Only enum types are allowed here
+  , retainedTypes :: [MDRef (Either DIType DISubprogram)]
+  , globals :: [MDRef DIGlobalVariableExpression]
+  , imports :: [MDRef DIImportedEntity]
+  , macros :: [MDRef DIMacroNode]
+  , dWOId :: Word64
+  , splitDebugInlining :: Bool
+  , debugInfoForProfiling :: Bool
+  , nameTableKind :: DebugNameTableKind
+  , rangesBaseAddress :: Bool
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#difile>
+data DIFile = File
+  { filename :: ShortByteString
+  , directory :: ShortByteString
+  , checksum :: Maybe ChecksumInfo
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data ChecksumInfo = ChecksumInfo
+  { checksumKind :: ChecksumKind
+  , checksumValue :: ShortByteString
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data ChecksumKind = MD5 | SHA1
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DILocalScope.html>
+data DILocalScope
+  = DILexicalBlockBase DILexicalBlockBase
+  | DISubprogram DISubprogram
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#disubprogram>
+data DISubprogram = Subprogram
+  { scope :: Maybe (MDRef DIScope)
+  , name :: ShortByteString
+  , linkageName :: ShortByteString
+  , file :: Maybe (MDRef DIFile)
+  , line :: Word32
+  , type' :: Maybe (MDRef DISubroutineType)
+  , localToUnit :: Bool
+  , definition :: Bool
+  , scopeLine :: Word32
+  , containingType :: Maybe (MDRef DIType)
+  , virtuality :: Virtuality
+  , virtualityIndex :: Word32
+  , thisAdjustment :: Int32
+  , flags :: [DIFlag]
+  , optimized :: Bool
+  , unit :: Maybe (MDRef DICompileUnit)
+  , templateParams :: [MDRef DITemplateParameter]
+  , declaration :: Maybe (MDRef DISubprogram)
+  , retainedNodes :: [MDRef DILocalVariable]
+  , thrownTypes :: [MDRef DIType]
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data Virtuality = NoVirtuality | Virtual | PureVirtual
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data BasicTypeTag = BaseType | UnspecifiedType
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- <https://llvm.org/doxygen/classllvm_1_1DIType.html>
+data DIType
+  = DIBasicType DIBasicType
+  | DICompositeType DICompositeType
+  | DIDerivedType DIDerivedType
+  | DISubroutineType DISubroutineType
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#dibasictype>
+data DIBasicType = BasicType
+  { name :: ShortByteString
+  , sizeInBits :: Word64
+  , alignInBits :: Word32
+  , encoding :: Maybe Encoding
+  , tag :: BasicTypeTag
+  , flags :: [DIFlag]
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#disubroutinetype>
+data DISubroutineType = SubroutineType
+  { flags :: [DIFlag]
+  , cc :: Word8
+  , typeArray :: [Maybe (MDRef DIType)]
+  -- ^ The first element is the return type, the following are the
+  -- operand types. `Nothing` corresponds to @void@.
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data DerivedTypeTag
+  = Typedef
+  | PointerType
+  | PtrToMemberType
+  | ReferenceType
+  | RValueReferenceType
+  | ConstType
+  | VolatileType
+  | RestrictType
+  | AtomicType
+  | Member
+  | Inheritance
+  | Friend
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#diderivedtype>
+data DIDerivedType =
+  DerivedType
+    { tag :: DerivedTypeTag
+    , name :: ShortByteString
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , scope :: Maybe (MDRef DIScope)
+    , baseType :: Maybe (MDRef DIType)
+    -- ^ This can be `Nothing` to represent @void *@
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    , offsetInBits :: Word64
+    , addressSpace :: Maybe Word32
+    , flags :: [DIFlag]
+    } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#dicompositetype>
+data DICompositeType
+  = DIArrayType
+    { subscripts :: [DISubrange]
+    , elementTy :: Maybe (MDRef DIType)
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    , flags :: [DIFlag]
+    }
+  | DIClassType
+    { scope :: Maybe (MDRef DIScope)
+    , name :: ShortByteString
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , flags :: [DIFlag]
+    , derivedFrom :: Maybe (MDRef DIType)
+    , elements :: [MDRef (Either DIDerivedType DISubprogram)]
+    -- ^ `DIDerivedType` with tag set to one of `Member`, `Inheritance`, `Friend`
+    -- or `DISubprogram` with `definition` set to `True`.
+    , vtableHolder :: Maybe (MDRef DIType)
+    , templateParams :: [DITemplateParameter]
+    , identifier :: ShortByteString
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    }
+  | DIEnumerationType
+    { scope :: Maybe (MDRef DIScope)
+    , name :: ShortByteString
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , values :: [DIEnumerator]
+    , baseType :: Maybe (MDRef DIType)
+    , identifier :: ShortByteString
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    }
+  | DIStructureType
+    { scope :: Maybe (MDRef DIScope)
+    , name :: ShortByteString
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , flags :: [DIFlag]
+    , derivedFrom :: Maybe (MDRef DIType)
+    , elements :: [MDRef (Either DIDerivedType DISubprogram)]
+    -- ^ `DIDerivedType` with tag set to one of `Member`, `Inheritance`, `Friend`
+    -- or `DISubprogram` with `definition` set to `True`.
+    , runtimeLang :: Word16
+    , vtableHolder :: Maybe (MDRef DIType)
+    , identifier :: ShortByteString
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    }
+  | DIUnionType
+    { scope :: Maybe (MDRef DIScope)
+    , name :: ShortByteString
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , flags :: [DIFlag]
+    , elements :: [MDRef (Either DIDerivedType DISubprogram)]
+    -- ^ `DIDerivedType` with tag set to one of `Member`, `Inheritance`, `Friend`
+    -- or `DISubprogram` with `definition` set to `True`.
+    , runtimeLang :: Word16
+    , identifier :: ShortByteString
+    , sizeInBits :: Word64
+    , alignInBits :: Word32
+    }
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data Encoding
+  = AddressEncoding
+  | BooleanEncoding
+  | FloatEncoding
+  | SignedEncoding
+  | SignedCharEncoding
+  | UnsignedEncoding
+  | UnsignedCharEncoding
+  | UTFEncoding
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+data TemplateValueParameterTag
+  = TemplateValueParameter
+  | GNUTemplateTemplateParam
+  | GNUTemplateParameterPack
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DITemplateParameter.html>
+data DITemplateParameter
+  = DITemplateTypeParameter
+    { name :: ShortByteString
+    , type' :: Maybe (MDRef DIType)
+    -- ^ For DITemplateTypeParameter this field is required,
+    -- for DITemplateValueParameter it is optional.
+    }
+  -- ^ <https://llvm.org/docs/LangRef.html#ditemplatetypeparameter>
+  | DITemplateValueParameter
+    { name :: ShortByteString
+    , type' :: Maybe (MDRef DIType)
+    , value :: Maybe Metadata
+    , tag :: TemplateValueParameterTag
+    }
+  -- ^ <https://llvm.org/docs/LangRef.html#ditemplatevalueparameter>
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DILexicalBlockBase.html>
+data DILexicalBlockBase
+  = DILexicalBlock
+    { scope :: MDRef DILocalScope
+    , file :: Maybe (MDRef DIFile)
+    , line :: Word32
+    , column :: Word16
+    }
+  -- ^ <https://llvm.org/docs/LangRef.html#dilexicalblock>
+  | DILexicalBlockFile
+    { scope :: MDRef DILocalScope
+    , file :: Maybe (MDRef DIFile)
+    , discriminator :: Word32
+    }
+  -- ^ <https://llvm.org/docs/LangRef.html#dilexicalblockfile>
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DIVariable.html>
+data DIVariable
+  = DIGlobalVariable DIGlobalVariable
+  | DILocalVariable DILocalVariable
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#diglobalvariable>
+data DIGlobalVariable = GlobalVariable
+  { name :: ShortByteString
+  , scope :: Maybe (MDRef DIScope)
+  , file :: Maybe (MDRef DIFile)
+  , line :: Word32
+  , type' :: Maybe (MDRef DIType)
+  , linkageName :: ShortByteString
+  , local :: Bool
+  , definition :: Bool
+  , staticDataMemberDeclaration :: Maybe (MDRef DIDerivedType)
+  , templateParams :: [MDRef DITemplateParameter]
+  , alignInBits :: Word32
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <https://llvm.org/docs/LangRef.html#dilocalvariable>
+data DILocalVariable = LocalVariable
+  { name :: ShortByteString
+  , scope :: MDRef DIScope
+  , file :: Maybe (MDRef DIFile)
+  , line :: Word32
+  , type' :: Maybe (MDRef DIType)
+  , flags :: [DIFlag]
+  , arg :: Word16
+  , alignInBits :: Word32
+  } deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/ParameterAttribute.hs b/src/LLVM/AST/ParameterAttribute.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/ParameterAttribute.hs
@@ -0,0 +1,33 @@
+-- | Module to allow importing 'ParameterAttribute' distinctly qualified.
+module LLVM.AST.ParameterAttribute where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#parameter-attributes>
+data ParameterAttribute
+    = Alignment Word64
+    | ByVal
+    | Dereferenceable Word64
+    | DereferenceableOrNull Word64
+    | ImmArg
+    | InAlloca
+    | InReg
+    | Nest
+    | NoAlias
+    | NoCapture
+    | NoFree
+    | NonNull
+    | ReadNone
+    | ReadOnly
+    | Returned
+    | SignExt
+    | SRet
+    | SwiftError
+    | SwiftSelf
+    | WriteOnly
+    | StringAttribute {
+        stringAttributeKind :: ShortByteString,
+        stringAttributeValue :: ShortByteString -- ^ Use "" for no value -- the two are conflated
+      }
+    | ZeroExt
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/RMWOperation.hs b/src/LLVM/AST/RMWOperation.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/RMWOperation.hs
@@ -0,0 +1,22 @@
+-- | Operations for the 'LLVM.AST.Instruction.AtomicRMW' instruction
+module LLVM.AST.RMWOperation where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#atomicrmw-instruction>
+data RMWOperation
+  = Xchg
+  | Add
+  | Sub
+  | And
+  | Nand
+  | Or
+  | Xor
+  | Max
+  | Min
+  | UMax
+  | UMin
+  | FAdd
+  | FSub
+  deriving (Eq, Ord, Read, Show, Data, Typeable, Generic)
+
diff --git a/src/LLVM/AST/ThreadLocalStorage.hs b/src/LLVM/AST/ThreadLocalStorage.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/ThreadLocalStorage.hs
@@ -0,0 +1,12 @@
+-- | Module to allow importing 'ThreadLocalStorage.Model' distinctly qualified.
+module LLVM.AST.ThreadLocalStorage where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#thread-local-storage-models>
+data Model
+    = GeneralDynamic
+    | LocalDynamic
+    | InitialExec
+    | LocalExec
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/AST/Type.hs b/src/LLVM/AST/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Type.hs
@@ -0,0 +1,102 @@
+-- | A representation of an LLVM type
+module LLVM.AST.Type where
+
+import LLVM.Prelude
+
+import LLVM.AST.AddrSpace
+import LLVM.AST.Name
+
+-- | LLVM supports some special formats floating point format. This type is to distinguish those format. Also see  <http://llvm.org/docs/LangRef.html#floating-point-types>
+data FloatingPointType
+  = HalfFP      -- ^ 16-bit floating point value
+  | FloatFP     -- ^ 32-bit floating point value
+  | DoubleFP    -- ^ 64-bit floating point value
+  | FP128FP     -- ^ 128-bit floating point value (112-bit mantissa)
+  | X86_FP80FP  -- ^ 80-bit floating point value (X87)
+  | PPC_FP128FP -- ^ 128-bit floating point value (two 64-bits)
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | <http://llvm.org/docs/LangRef.html#type-system>
+data Type
+  -- | <http://llvm.org/docs/LangRef.html#void-type>
+  = VoidType
+  -- | <http://llvm.org/docs/LangRef.html#integer-type>
+  | IntegerType { typeBits :: Word32 }
+  -- | <http://llvm.org/docs/LangRef.html#pointer-type>
+  | PointerType { pointerReferent :: Type, pointerAddrSpace :: AddrSpace }
+  -- | <http://llvm.org/docs/LangRef.html#floating-point-types>
+  | FloatingPointType { floatingPointType :: FloatingPointType }
+  -- | <http://llvm.org/docs/LangRef.html#function-type>
+  | FunctionType { resultType :: Type, argumentTypes :: [Type], isVarArg :: Bool }
+  -- | <http://llvm.org/docs/LangRef.html#vector-type>
+  | VectorType { nVectorElements :: Word32, elementType :: Type }
+  -- | <http://llvm.org/docs/LangRef.html#structure-type>
+  | StructureType { isPacked :: Bool, elementTypes :: [Type] }
+  -- | <http://llvm.org/docs/LangRef.html#array-type>
+  | ArrayType { nArrayElements :: Word64, elementType :: Type }
+  -- | <http://llvm.org/docs/LangRef.html#opaque-structure-types>
+  | NamedTypeReference Name
+  -- | <http://llvm.org/docs/LangRef.html#metadata-type>
+  | MetadataType -- only to be used as a parameter type for a few intrinsics
+  -- | <http://llvm.org/docs/LangRef.html#label-type>
+  | LabelType -- only to be used as the type of block names
+  -- | <http://llvm.org/docs/LangRef.html#token-type>
+  | TokenType
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | An abbreviation for 'VoidType'
+void :: Type
+void = VoidType
+
+-- | An abbreviation for 'IntegerType' 1
+i1 :: Type
+i1 = IntegerType 1
+
+-- | An abbreviation for 'IntegerType' 8
+i8 :: Type
+i8 = IntegerType 8
+
+-- | An abbreviation for 'IntegerType' 16
+i16 :: Type
+i16 = IntegerType 16
+
+-- | An abbreviation for 'IntegerType' 32
+i32 :: Type
+i32 = IntegerType 32
+
+-- | An abbreviation for 'IntegerType' 64
+i64 :: Type
+i64 = IntegerType 64
+
+-- | An abbreviation for 'IntegerType' 128
+i128 :: Type
+i128 = IntegerType 128
+
+-- | An abbreviation for 'PointerType' t ('AddrSpace' 0)
+ptr :: Type -> Type
+ptr t = PointerType t (AddrSpace 0)
+
+-- | An abbreviation for 'FloatingPointType' 'HalfFP'
+half :: Type
+half = FloatingPointType HalfFP
+
+-- | An abbreviation for 'FloatingPointType' 'FloatFP'
+float :: Type
+float = FloatingPointType FloatFP
+
+-- | An abbreviation for 'FloatingPointType' 'DoubleFP'
+double :: Type
+double = FloatingPointType DoubleFP
+
+-- | An abbreviation for 'FloatingPointType' 'FP128FP'
+fp128 :: Type
+fp128 = FloatingPointType FP128FP
+
+-- | An abbreviation for 'FloatingPointType' 'X86_FP80FP'
+x86_fp80 :: Type
+x86_fp80 = FloatingPointType X86_FP80FP
+
+-- | An abbreviation for 'FloatingPointType' 'PPC_FP128FP'
+ppc_fp128 :: Type
+ppc_fp128 = FloatingPointType PPC_FP128FP
+
diff --git a/src/LLVM/AST/Typed.hs b/src/LLVM/AST/Typed.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Typed.hs
@@ -0,0 +1,208 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | Querying the type of LLVM expressions
+module LLVM.AST.Typed (
+  Typed(..),
+  getElementType,
+  indexTypeByConstants,
+  indexTypeByOperands,
+  extractValueType,
+) where
+
+import LLVM.Prelude
+
+import Control.Monad.State (gets)
+import qualified Data.Map.Lazy as Map
+import qualified Data.Either as Either
+import GHC.Stack
+
+import LLVM.AST
+import LLVM.AST.Global
+import LLVM.AST.Type
+
+import LLVM.IRBuilder.Module
+
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.Float as F
+
+class Typed a where
+  typeOf :: (HasCallStack, MonadModuleBuilder m) => a -> m (Either String Type)
+
+instance Typed Operand where
+  typeOf (LocalReference t _) = return $ Right t
+  typeOf (ConstantOperand c)  = typeOf c
+  typeOf _                    = return $ Right MetadataType
+
+instance Typed CallableOperand where
+  typeOf (Right op) = typeOf op
+  typeOf (Left _) = return $ Left "typeOf inline assembler is not defined. (Malformed AST)"
+
+instance Typed C.Constant where
+  typeOf (C.Int bits _)       = return $ Right $ IntegerType bits
+  typeOf (C.Float t)          = typeOf t
+  typeOf (C.Null t)           = return $ Right t
+  typeOf (C.AggregateZero t)  = return $ Right t
+  typeOf (C.Struct {..}) = case structName of
+                             Nothing -> do
+                               mvtys <- mapM typeOf memberValues
+                               case (all Either.isRight mvtys) of
+                                 True -> return $ Right $ StructureType isPacked $ Either.rights mvtys
+                                 False -> do
+                                   let (Left s) = head $ filter Either.isLeft mvtys
+                                   return $ Left $ "Could not deduce type for struct field: " ++ s
+                             Just sn -> return $ Right $ NamedTypeReference sn
+  typeOf (C.Array {..})  = return $ Right $ ArrayType (fromIntegral $ length memberValues) memberType
+  typeOf (C.Vector {..}) = case memberValues of
+                             []    -> return $ Left "Vectors of size zero are not allowed. (Malformed AST)"
+                             (x:_) -> do
+                               t <- typeOf x
+                               case t of
+                                 (Left _) -> return t
+                                 (Right t') -> return $ Right $ VectorType (fromIntegral $ length memberValues) t'
+
+  typeOf (C.Undef t)     = return $ Right t
+  typeOf (C.BlockAddress {}) = return $ Right $ ptr i8
+  typeOf (C.GlobalReference t _) = return $ Right t
+  typeOf (C.Add {..})     = typeOf operand0
+  typeOf (C.FAdd {..})    = typeOf operand0
+  typeOf (C.FDiv {..})    = typeOf operand0
+  typeOf (C.FRem {..})    = typeOf operand0
+  typeOf (C.Sub {..})     = typeOf operand0
+  typeOf (C.FSub {..})    = typeOf operand0
+  typeOf (C.Mul {..})     = typeOf operand0
+  typeOf (C.FMul {..})    = typeOf operand0
+  typeOf (C.UDiv {..})    = typeOf operand0
+  typeOf (C.SDiv {..})    = typeOf operand0
+  typeOf (C.URem {..})    = typeOf operand0
+  typeOf (C.SRem {..})    = typeOf operand0
+  typeOf (C.Shl {..})     = typeOf operand0
+  typeOf (C.LShr {..})    = typeOf operand0
+  typeOf (C.AShr {..})    = typeOf operand0
+  typeOf (C.And {..})     = typeOf operand0
+  typeOf (C.Or  {..})     = typeOf operand0
+  typeOf (C.Xor {..})     = typeOf operand0
+  typeOf (C.GetElementPtr {..}) = do
+    aty <- typeOf address
+    case aty of
+      (Left _) -> return aty
+      (Right aty') -> indexTypeByConstants aty' indices
+  typeOf (C.Trunc {..})    = return $ Right type'
+  typeOf (C.ZExt {..})     = return $ Right type'
+  typeOf (C.SExt {..})     = return $ Right type'
+  typeOf (C.FPToUI {..})   = return $ Right type'
+  typeOf (C.FPToSI {..})   = return $ Right type'
+  typeOf (C.UIToFP {..})   = return $ Right type'
+  typeOf (C.SIToFP {..})   = return $ Right type'
+  typeOf (C.FPTrunc {..})  = return $ Right type'
+  typeOf (C.FPExt {..})    = return $ Right type'
+  typeOf (C.PtrToInt {..}) = return $ Right type'
+  typeOf (C.IntToPtr {..}) = return $ Right type'
+  typeOf (C.BitCast {..})  = return $ Right type'
+  typeOf (C.ICmp {..})    = do
+    t <- typeOf operand0
+    case t of
+      (Left _) -> return t
+      (Right (VectorType n _)) -> return $ Right $ VectorType n i1
+      (Right _) -> return $ Right i1
+  typeOf (C.FCmp {..})    = do
+    t <- typeOf operand0
+    case t of
+      (Left _) -> return t
+      (Right (VectorType n _)) -> return $ Right $ VectorType n i1
+      (Right _) -> return $ Right i1
+  typeOf (C.Select {..})  = typeOf trueValue
+  typeOf (C.ExtractElement {..})  = do
+    t <- typeOf vector
+    case t of
+      (Left _) -> return t
+      (Right (VectorType _ t')) -> return $ Right t'
+      (Right _) -> return $ Left "The first operand of an extractelement instruction is a value of vector type. (Malformed AST)"
+  typeOf (C.InsertElement {..})   = typeOf vector
+  typeOf (C.ShuffleVector {..})   = do
+    t0 <- typeOf operand0
+    tm <- typeOf mask
+    case (t0, tm) of
+      (Right (VectorType _ t), Right (VectorType m _)) -> return $ Right $ VectorType m t
+      _ -> return $ Left "The first operand of an shufflevector instruction is a value of vector type. (Malformed AST)"
+  typeOf (C.ExtractValue {..})    = do
+    t <- typeOf aggregate
+    case t of
+      (Left _) -> return t
+      (Right t') -> extractValueType indices' t'
+  typeOf (C.InsertValue {..})   = typeOf aggregate
+  typeOf (C.TokenNone)          = return $ Right TokenType
+  typeOf (C.AddrSpaceCast {..}) = return $ Right type'
+
+-- | Index into a type using a list of 'Constant' values. Returns a pointer type whose referent is the indexed type, or an error message if indexing was not possible.
+indexTypeByConstants :: (HasCallStack, MonadModuleBuilder m) => Type -> [C.Constant] -> m (Either String Type)
+indexTypeByConstants ty [] = return $ Right $ ptr ty
+indexTypeByConstants (PointerType ty _) (_:is) = indexTypeByConstants ty is
+indexTypeByConstants (StructureType _ elTys) (C.Int 32 val:is) =
+  indexTypeByConstants (elTys !! fromIntegral val) is
+indexTypeByConstants (StructureType _ _) (i:_) =
+  return $ Left $ "Indices into structures should be 32-bit integer constants. (Malformed AST): " ++ show i
+indexTypeByConstants (VectorType _ elTy) (_:is) = indexTypeByConstants elTy is
+indexTypeByConstants (ArrayType _ elTy) (_:is) = indexTypeByConstants elTy is
+indexTypeByConstants (NamedTypeReference n) is = do
+  mayTy <- liftModuleState (gets (Map.lookup n . builderTypeDefs))
+  case mayTy of
+    Nothing -> return $ Left $ "Couldn’t resolve typedef for: " ++ show n
+    Just ty -> indexTypeByConstants ty is
+indexTypeByConstants ty _ = return $ Left $ "Expecting aggregate type. (Malformed AST): " ++ show ty
+
+-- | Index into a type using a list of 'Operand' values. Returns a pointer type whose referent is the indexed type, or an error message if indexing was not possible.
+indexTypeByOperands :: (HasCallStack, MonadModuleBuilder m) => Type -> [Operand] -> m (Either String Type)
+indexTypeByOperands ty [] = return $ Right $ ptr ty
+indexTypeByOperands (PointerType ty _) (_:is) = indexTypeByOperands ty is
+indexTypeByOperands (StructureType _ elTys) (ConstantOperand (C.Int 32 val):is) =
+  indexTypeByOperands (elTys !! fromIntegral val) is
+indexTypeByOperands (StructureType _ _) (i:_) =
+  return $ Left $ "Indices into structures should be 32-bit integer constants. (Malformed AST): " ++ show i
+indexTypeByOperands (VectorType _ elTy) (_:is) = indexTypeByOperands elTy is
+indexTypeByOperands (ArrayType _ elTy) (_:is) = indexTypeByOperands elTy is
+indexTypeByOperands (NamedTypeReference n) is = do
+  mayTy <- liftModuleState (gets (Map.lookup n . builderTypeDefs))
+  case mayTy of
+    Nothing -> return $ Left $ "Couldn’t resolve typedef for: " ++ show n
+    Just ty -> indexTypeByOperands ty is
+indexTypeByOperands ty _ = return $ Left $ "Expecting aggregate type. (Malformed AST): " ++ show ty
+
+getElementType :: Type -> Either String Type
+getElementType (PointerType t _) = Right t
+getElementType t = Left $ "Expecting pointer type. (Malformed AST): " ++ show t
+
+extractValueType :: (HasCallStack, MonadModuleBuilder m) => [Word32] -> Type -> m (Either String Type)
+extractValueType [] ty = return $ Right ty
+extractValueType (i : is) (ArrayType numEls elTy)
+  | fromIntegral i < numEls = extractValueType is elTy
+  | fromIntegral i >= numEls = return $ Left $ "Expecting valid index into array type. (Malformed AST): " ++ show i
+extractValueType (i : is) (StructureType _ elTys)
+  | fromIntegral i < length elTys = extractValueType is (elTys !! fromIntegral i)
+  | otherwise = return $ Left $ "Expecting valid index into structure type. (Malformed AST): " ++ show i
+extractValueType _ ty = return $ Left $ "Expecting vector type. (Malformed AST): " ++ show ty
+
+instance Typed F.SomeFloat where
+  typeOf (F.Half _)          = return $ Right $ FloatingPointType HalfFP
+  typeOf (F.Single _)        = return $ Right $ FloatingPointType FloatFP
+  typeOf (F.Double _)        = return $ Right $ FloatingPointType DoubleFP
+  typeOf (F.Quadruple _ _)   = return $ Right $ FloatingPointType FP128FP
+  typeOf (F.X86_FP80 _ _)    = return $ Right $ FloatingPointType X86_FP80FP
+  typeOf (F.PPC_FP128 _ _)   = return $ Right $ FloatingPointType PPC_FP128FP
+
+instance Typed Global where
+  typeOf (GlobalVariable {..}) = return $ Right $ type'
+  typeOf (GlobalAlias {..})    = return $ Right $ type'
+  typeOf (Function {..})       = do
+    let (params, isVarArg) = parameters
+    ptys <- mapM typeOf params
+    case (all Either.isRight ptys) of
+      True -> return $ Right $ FunctionType returnType (Either.rights ptys) isVarArg
+      False -> do
+        let (Left s) = head $ filter Either.isLeft ptys
+        return $ Left $ "Could not deduce type for function parameter: " ++ s
+
+instance Typed Parameter where
+  typeOf (Parameter t _ _) = return $ Right t
+
+instance Typed [Int32] where
+  typeOf mask = return $ Right $ VectorType (fromIntegral $ length mask) i32
diff --git a/src/LLVM/AST/Visibility.hs b/src/LLVM/AST/Visibility.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/AST/Visibility.hs
@@ -0,0 +1,8 @@
+-- | Module to allow importing 'Visibility' distinctly qualified.
+module LLVM.AST.Visibility where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/LangRef.html#visibility>
+data Visibility = Default | Hidden | Protected
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/Analysis.hs b/src/LLVM/Analysis.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Analysis.hs
@@ -0,0 +1,8 @@
+-- | functionality for analyzing 'LLVM.Module.Module's.  Much of the analysis
+-- possible with LLVM is managed internally, as needed by 'Transforms', and so is not
+-- yet exposed here.
+module LLVM.Analysis (
+  verify
+  ) where
+
+import LLVM.Internal.Analysis
diff --git a/src/LLVM/CodeGenOpt.hs b/src/LLVM/CodeGenOpt.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/CodeGenOpt.hs
@@ -0,0 +1,12 @@
+-- | Code generation options, used in specifying TargetMachine
+module LLVM.CodeGenOpt where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1CodeGenOpt.html>
+data Level
+    = None
+    | Less
+    | Default
+    | Aggressive
+    deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/CodeModel.hs b/src/LLVM/CodeModel.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/CodeModel.hs
@@ -0,0 +1,14 @@
+-- | Code model, used in specifying TargetMachine
+module LLVM.CodeModel where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1CodeModel.html>
+data Model
+    = Default
+    | JITDefault
+    | Small
+    | Kernel
+    | Medium
+    | Large
+    deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/CommandLine.hs b/src/LLVM/CommandLine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/CommandLine.hs
@@ -0,0 +1,8 @@
+-- | Tools for processing command line arguments, for command line tools build
+-- with llvm (or for other uses forced into pretending to be such to get at (ack)
+-- global state).
+module LLVM.CommandLine (
+  parseCommandLineOptions
+) where
+
+import LLVM.Internal.CommandLine
diff --git a/src/LLVM/Context.hs b/src/LLVM/Context.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Context.hs
@@ -0,0 +1,9 @@
+-- | functions for the LLVM Context object which holds thread-scope state
+module LLVM.Context (
+  Context,
+  withContext,
+  createContext,
+  disposeContext
+  ) where
+
+import LLVM.Internal.Context
diff --git a/src/LLVM/DataLayout.hs b/src/LLVM/DataLayout.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/DataLayout.hs
@@ -0,0 +1,127 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.DataLayout (
+ dataLayoutToString,
+ parseDataLayout
+ ) where
+
+import LLVM.Prelude
+
+import Control.Monad.Trans.Except
+
+import Data.Attoparsec.ByteString
+import Data.Attoparsec.ByteString.Char8
+import Data.ByteString.Char8 as ByteString hiding (map, foldr)
+import qualified Data.List as List
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+
+import LLVM.AST.DataLayout
+import LLVM.AST.AddrSpace
+
+dataLayoutToString :: DataLayout -> ByteString
+dataLayoutToString dl =
+  let sAlignmentInfo :: AlignmentInfo -> ByteString
+      sAlignmentInfo (AlignmentInfo abi pref) =
+        pack (show abi) <>
+        if pref /= abi
+          then ":" <> pack (show pref)
+          else ""
+      sTriple :: (Word32, AlignmentInfo) -> ByteString
+      sTriple (s, ai) = pack (show s) <> ":" <> sAlignmentInfo ai
+      atChar at = case at of
+        IntegerAlign -> "i"
+        VectorAlign -> "v"
+        FloatAlign -> "f"
+      manglingChar m = case m of
+        ELFMangling -> "e"
+        MIPSMangling -> "m"
+        MachOMangling -> "o"
+        WindowsCOFFMangling -> "w"
+      oneOpt f accessor = maybe [] ((:[]) . f) (accessor dl)
+      defDl = defaultDataLayout BigEndian
+      nonDef :: Eq a => (DataLayout -> [a]) -> [a]
+      nonDef f = (f dl) List.\\ (f defDl)
+  in
+  ByteString.intercalate "-" (
+    [case endianness dl of BigEndian -> "E"; LittleEndian -> "e"]
+    ++
+    (oneOpt (("m:" <>) . manglingChar) mangling)
+    ++
+    [
+      "p" <> (if a == 0 then "" else pack (show a)) <> ":" <> sTriple t
+      | (AddrSpace a, t) <- nonDef (Map.toList . pointerLayouts)
+    ] ++ [
+      atChar at <> sTriple (s, ai)
+      | ((at, s), ai) <- nonDef (Map.toList . typeLayouts)
+    ] ++ [
+      "a:" <> sAlignmentInfo ai | ai <- nonDef (pure . aggregateLayout)
+    ] ++
+    (oneOpt (("n"<>) . (ByteString.intercalate ":") . map (pack . show) . Set.toList) nativeSizes)
+    ++
+    (oneOpt (("S"<>) . pack . show) stackAlignment)
+  )
+
+-- | Parse a 'DataLayout', given a default Endianness should one not be specified in the
+-- string to be parsed. LLVM itself uses BigEndian as the default: thus pass BigEndian to
+-- be conformant or LittleEndian to be righteously defiant.
+parseDataLayout :: Endianness -> ByteString -> Except String (Maybe DataLayout)
+parseDataLayout _ "" = pure Nothing
+parseDataLayout defaultEndianness str =
+  let
+    num :: Parser Word32
+    num = read <$> many1 digit
+    alignmentInfo :: Parser AlignmentInfo
+    alignmentInfo = do
+      abi <- num
+      pref <- optional $ char ':' *> num
+      let pref' = fromMaybe abi pref
+      pure $ AlignmentInfo abi pref'
+    triple :: Parser (Word32, AlignmentInfo)
+    triple = do
+      s <- num
+      ai <- char ':' *> alignmentInfo
+      pure (s, ai)
+    parseSpec :: Parser (DataLayout -> DataLayout)
+    parseSpec = choice [
+      char 'e' *> pure (\dl -> dl { endianness = LittleEndian }),
+      char 'E' *> pure (\dl -> dl { endianness = BigEndian }),
+      do
+        m <- char 'm' *> char ':' *> choice [
+              char 'e' *> pure ELFMangling,
+              char 'm' *> pure MIPSMangling,
+              char 'o' *> pure MachOMangling,
+              char 'w' *> pure WindowsCOFFMangling
+             ]
+        pure $ \dl -> dl { mangling = Just m },
+      do
+        n <- char 'S' *> num
+        pure $ \dl -> dl { stackAlignment = Just n },
+      do
+        a <- char 'p' *> (AddrSpace <$> option 0 (read <$> many1 digit))
+        t <- char ':' *> triple
+        pure $ \dl -> dl { pointerLayouts = Map.insert a t (pointerLayouts dl) },
+      do
+        -- Ignore this obsolete approach to stack alignment.  After the 3.4 release,
+        -- this is never generated, still parsed but ignored.  Comments suggest
+        -- it will no longer be parsed after 4.0.
+        void $ char 's' *> triple
+        pure id,
+      do
+        at <- choice [
+               char 'i' *> pure IntegerAlign,
+               char 'v' *> pure VectorAlign,
+               char 'f' *> pure FloatAlign
+              ]
+        (sz, ai) <- triple
+        pure $ \dl -> dl { typeLayouts = Map.insert (at, sz) ai (typeLayouts dl) },
+      do
+        ai <- char 'a' *> char ':' *> alignmentInfo
+        pure $ \dl -> dl { aggregateLayout = ai },
+      do
+        ns <- char 'n' *> num `sepBy` (char ':')
+        pure $ \dl -> dl { nativeSizes = Just (Set.fromList ns) }
+     ]
+  in
+    case parseOnly (parseSpec `sepBy` (char '-')) str of
+      Left _ -> throwE $ "ill-formed data layout: " ++ show str
+      Right fs -> pure . Just $ foldr ($) (defaultDataLayout defaultEndianness) fs
diff --git a/src/LLVM/Diagnostic.hs b/src/LLVM/Diagnostic.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Diagnostic.hs
@@ -0,0 +1,33 @@
+-- | Diagnostics describe parse errors
+module LLVM.Diagnostic (
+  DiagnosticKind(..),
+  Diagnostic(..),
+  diagnosticDisplay
+ ) where
+
+import LLVM.Prelude
+
+-- | What kind of problem does a diagnostic describe?
+data DiagnosticKind 
+  = ErrorKind
+  | WarningKind
+  | NoteKind
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | A 'Diagnostic' described a problem during parsing of LLVM IR
+data Diagnostic = Diagnostic {
+    lineNumber :: Int,
+    columnNumber :: Int,
+    diagnosticKind :: DiagnosticKind,
+    filename :: String,
+    message :: String,
+    lineContents :: String
+  }
+  deriving (Eq, Ord, Read, Show)
+
+-- | Convert a 'Diagnostic' to a printable form.
+diagnosticDisplay :: Diagnostic -> String
+diagnosticDisplay d = 
+  (filename d) ++ ":" ++ show (lineNumber d) ++ ":" ++ show (columnNumber d)
+  ++ ":\n" ++ show (diagnosticKind d) ++ ": " ++ (message d) ++ "\n"
+  ++ (lineContents d) ++ "\n"
diff --git a/src/LLVM/Exception.hs b/src/LLVM/Exception.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Exception.hs
@@ -0,0 +1,72 @@
+{-|
+This module lists all of the exceptions thrown by 'llvm-hs' itself.
+Note that other exceptions can potentially be thrown
+by the underlying libraries, e.g., for functions doing file IO.
+-}
+module LLVM.Exception where
+
+import LLVM.Prelude
+
+import Control.Monad.Catch
+
+-- | Indicates an error during the translation of the AST provided by
+-- 'llvm-hs-pure' to LLVM’s internal representation.
+data EncodeException =
+  EncodeException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception EncodeException
+
+-- | Indicates an error during the translation of LLVM’s internal representation
+-- to the AST provided 'llvm-hs-pure'.
+data DecodeException =
+  DecodeException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception DecodeException
+
+-- | Indicates an error during the parsing of a module. This is used
+-- for errors encountered when parsing LLVM’s human readable assembly
+-- format and when parsing the binary bitcode format.
+data ParseFailureException =
+  ParseFailureException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception ParseFailureException
+
+-- | Indicates an error during the linking of two modules.
+data LinkException =
+  LinkException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception LinkException
+
+-- | Indicates an error during the creation of a
+-- <http://llvm.org/docs/doxygen/html/classllvm_1_1raw__fd__ostream.html raw_fd_ostream>.
+-- This could be caused by a nonexisting file path.
+data FdStreamException =
+  FdStreamException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception FdStreamException
+
+-- | Indicates an error during a call to 'LLVM.Internal.Module.targetMachineEmit'.
+data TargetMachineEmitException =
+  TargetMachineEmitException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception TargetMachineEmitException
+
+-- | Indicates a failure to find the target.
+data LookupTargetException =
+  LookupTargetException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception LookupTargetException
+
+-- | Indicates an error during the verification of a module.
+data VerifyException =
+  VerifyException !String
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception VerifyException
diff --git a/src/LLVM/ExecutionEngine.hs b/src/LLVM/ExecutionEngine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/ExecutionEngine.hs
@@ -0,0 +1,8 @@
+-- | Tools for JIT execution
+module LLVM.ExecutionEngine (
+  ExecutionEngine(..),
+  ExecutableModule,
+  MCJIT, withMCJIT
+  ) where
+
+import LLVM.Internal.ExecutionEngine
diff --git a/src/LLVM/IRBuilder.hs b/src/LLVM/IRBuilder.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder.hs
@@ -0,0 +1,8 @@
+module LLVM.IRBuilder
+  (module X)
+  where
+
+import LLVM.IRBuilder.Monad as X
+import LLVM.IRBuilder.Instruction as X
+import LLVM.IRBuilder.Module as X
+import LLVM.IRBuilder.Constant as X
diff --git a/src/LLVM/IRBuilder/Constant.hs b/src/LLVM/IRBuilder/Constant.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder/Constant.hs
@@ -0,0 +1,41 @@
+module LLVM.IRBuilder.Constant where
+import           Data.Word
+import           LLVM.Prelude
+import           LLVM.AST             hiding (args, dests)
+import           LLVM.AST.Typed
+
+import           LLVM.AST.Constant
+import           LLVM.AST.Float
+import           LLVM.IRBuilder.Module
+
+import GHC.Stack
+
+int64 :: Integer -> Operand
+int64 = ConstantOperand . Int 64
+int32 :: Integer -> Operand
+int32 = ConstantOperand . Int 32
+int16 :: Integer -> Operand
+int16 = ConstantOperand . Int 16
+int8 :: Integer -> Operand
+int8  = ConstantOperand . Int 8
+bit :: Integer -> Operand
+bit   = ConstantOperand . Int 1
+
+double :: Double -> Operand
+double = ConstantOperand . Float . Double
+
+single :: Float -> Operand
+single = ConstantOperand . Float . Single
+
+half :: Word16 -> Operand
+half = ConstantOperand . Float . Half
+
+struct :: Maybe Name -> Bool -> [Constant] -> Operand
+struct nm packing members = ConstantOperand $ Struct nm packing members
+
+array :: (HasCallStack, MonadModuleBuilder m) => [Constant] -> m Operand
+array members = do
+  thm <- typeOf $ head members
+  case thm of
+    (Left s) -> error s
+    (Right thm') -> return $ ConstantOperand $ Array thm' members
diff --git a/src/LLVM/IRBuilder/Instruction.hs b/src/LLVM/IRBuilder/Instruction.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder/Instruction.hs
@@ -0,0 +1,432 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module LLVM.IRBuilder.Instruction where
+
+import Prelude hiding (and, or, pred)
+
+import Data.Word
+import Data.Char (ord)
+import GHC.Int
+import GHC.Stack
+
+import LLVM.AST hiding (args, dests)
+import LLVM.AST.Type as AST
+import LLVM.AST.Typed
+import LLVM.AST.ParameterAttribute
+import qualified LLVM.AST as AST
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.IntegerPredicate as IP
+import qualified LLVM.AST.FloatingPointPredicate as FP
+
+import LLVM.AST.Global
+import LLVM.AST.Linkage
+
+import LLVM.IRBuilder.Monad
+import LLVM.IRBuilder.Module
+
+-- | See <https://llvm.org/docs/LangRef.html#fneg-instruction reference>.
+fneg :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> m Operand
+fneg a = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FNeg noFastMathFlags a []
+
+-- | See <https://llvm.org/docs/LangRef.html#fadd-instruction reference>.
+fadd :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+fadd a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FAdd noFastMathFlags a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#fmul-instruction reference>.
+fmul :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+fmul a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FMul noFastMathFlags a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#fsub-instruction reference>.
+fsub :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+fsub a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FSub noFastMathFlags a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#fdiv-instruction reference>.
+fdiv :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+fdiv a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FDiv noFastMathFlags a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#frem-instruction reference>.
+frem :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+frem a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ FRem noFastMathFlags a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#add-instruction reference>.
+add :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+add a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Add False False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#mul-instruction reference>.
+mul :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+mul a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Mul False False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#sub-instruction reference>.
+sub :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+sub a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Sub False False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#udiv-instruction reference>.
+udiv :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+udiv a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ UDiv False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#sdiv-instruction reference>.
+sdiv :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+sdiv a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ SDiv False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#urem-instruction reference>.
+urem :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+urem a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ URem a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#srem-instruction reference>.
+srem :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+srem a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ SRem a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#shl-instruction reference>.
+shl :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+shl a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Shl False False a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#lshl-instruction reference>.
+lshr :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+lshr a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ LShr True a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#ashl-instruction reference>.
+ashr :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+ashr a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ AShr True a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#and-instruction reference>.
+and :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+and a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ And a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#or-instruction reference>.
+or :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+or a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Or a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#xor-instruction reference>.
+xor :: (MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+xor a b = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ Xor a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#alloca-instruction reference>.
+alloca :: MonadIRBuilder m => Type -> Maybe Operand -> Word32 -> m Operand
+alloca ty count align = emitInstr (ptr ty) $ Alloca ty count align []
+
+-- | See <https://llvm.org/docs/LangRef.html#load-instruction reference>.
+load :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Word32 -> m Operand
+load a align = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> do
+      let retty = case ta' of
+                    PointerType ty _ -> ty
+                    _ -> error "Cannot load non-pointer (Malformed AST)."
+      emitInstr retty $ Load False a Nothing align []
+
+-- | See <https://llvm.org/docs/LangRef.html#store-instruction reference>.
+store :: MonadIRBuilder m => Operand -> Word32 -> Operand -> m ()
+store addr align val = emitInstrVoid $ Store False addr val Nothing align []
+
+-- | Emit the @getelementptr@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#getelementptr-instruction reference>.
+gep :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> [Operand] -> m Operand
+gep addr is = do
+  ta <- typeOf addr
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> do
+      ty <- indexTypeByOperands ta' is
+      case ty of
+        (Left s) -> error s
+        (Right ty') -> emitInstr ty' (GetElementPtr False addr is [])
+
+-- | Emit the @trunc ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#trunc-to-instruction reference>.
+trunc :: MonadIRBuilder m => Operand -> Type -> m Operand
+trunc a to = emitInstr to $ Trunc a to []
+
+-- | Emit the @fptrunc ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#fptrunc-to-instruction reference>.
+fptrunc :: MonadIRBuilder m => Operand -> Type -> m Operand
+fptrunc a to = emitInstr to $ FPTrunc a to []
+
+-- | Emit the @zext ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#zext-to-instruction reference>.
+zext :: MonadIRBuilder m => Operand -> Type -> m Operand
+zext a to = emitInstr to $ ZExt a to []
+
+-- | Emit the @sext ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#sext-to-instruction reference>.
+sext :: MonadIRBuilder m => Operand -> Type -> m Operand
+sext a to = emitInstr to $ SExt a to []
+
+-- | Emit the @fptoui ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#fptoui-to-instruction reference>.
+fptoui :: MonadIRBuilder m => Operand -> Type -> m Operand
+fptoui a to = emitInstr to $ FPToUI a to []
+
+-- | Emit the @fptosi ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#fptosi-to-instruction reference>.
+fptosi :: MonadIRBuilder m => Operand -> Type -> m Operand
+fptosi a to = emitInstr to $ FPToSI a to []
+
+-- | Emit the @fpext ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#fpext-to-instruction reference>.
+fpext :: MonadIRBuilder m => Operand -> Type -> m Operand
+fpext a to = emitInstr to $ FPExt a to []
+
+-- | Emit the @uitofp ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#uitofp-to-instruction reference>.
+uitofp :: MonadIRBuilder m => Operand -> Type -> m Operand
+uitofp a to = emitInstr to $ UIToFP a to []
+
+-- | Emit the @sitofp ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#sitofp-to-instruction reference>.
+sitofp :: MonadIRBuilder m => Operand -> Type -> m Operand
+sitofp a to = emitInstr to $ SIToFP a to []
+
+-- | Emit the @ptrtoint ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#ptrtoint-to-instruction reference>.
+ptrtoint :: MonadIRBuilder m => Operand -> Type -> m Operand
+ptrtoint a to = emitInstr to $ PtrToInt a to []
+
+-- | Emit the @inttoptr ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#inttoptr-to-instruction reference>.
+inttoptr :: MonadIRBuilder m => Operand -> Type -> m Operand
+inttoptr a to = emitInstr to $ IntToPtr a to []
+
+-- | Emit the @bitcast ... to@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#bitcast-to-instruction reference>.
+bitcast :: MonadIRBuilder m => Operand -> Type -> m Operand
+bitcast a to = emitInstr to $ BitCast a to []
+
+-- | See <https://llvm.org/docs/LangRef.html#extractelement-instruction reference>.
+extractElement :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> m Operand
+extractElement v i = do
+  tv <- typeOf v
+  let elemTyp = case tv of
+                  (Left s) -> error s
+                  (Right (VectorType _ typ)) -> typ
+                  (Right typ) -> error $ "extractElement: Expected a vector type but got " ++ show typ ++ " (Malformed AST)."
+  emitInstr elemTyp $ ExtractElement v i []
+
+-- | See <https://llvm.org/docs/LangRef.html#insertelement-instruction reference>.
+insertElement :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> Operand -> m Operand
+insertElement v e i = do
+  tv <- typeOf v
+  case tv of
+    (Left s) -> error s
+    (Right tv') -> emitInstr tv' $ InsertElement v e i []
+
+-- | See <https://llvm.org/docs/LangRef.html#shufflevector-instruction reference>.
+shuffleVector :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> [Int32] -> m Operand
+shuffleVector a b m = do
+  ta <- typeOf a
+  tm <- typeOf m
+  let retType = case (ta, tm) of
+                  (Right (VectorType _ elemTyp), Right (VectorType maskLength _)) -> VectorType maskLength elemTyp
+                  _ -> error "shuffleVector: Expected two vectors and a vector mask"
+  emitInstr retType $ ShuffleVector a b m []
+
+-- | See <https://llvm.org/docs/LangRef.html#extractvalue-instruction reference>.
+extractValue :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> [Word32] -> m Operand
+extractValue a i = do
+  ta <- typeOf a
+  let aggType = case ta of
+                  (Left s) -> error s
+                  (Right typ@ArrayType{}) -> typ
+                  (Right typ@NamedTypeReference{}) -> typ
+                  (Right typ@StructureType{}) -> typ
+                  (Right typ) -> error $ "extractValue: Expecting structure or array type but got " ++ show typ ++ " (Malformed AST)."
+  retType <- indexTypeByOperands aggType (map (ConstantOperand . C.Int 32 . fromIntegral) i)
+  case retType of
+    (Left s) -> error s
+    (Right retType') -> emitInstr (pointerReferent retType') $ ExtractValue a i []
+
+-- | See <https://llvm.org/docs/LangRef.html#insertvalue-instruction reference>.
+insertValue :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> [Word32] -> m Operand
+insertValue a e i = do
+  ta <- typeOf a
+  case ta of
+    (Left s) -> error s
+    (Right ta') -> emitInstr ta' $ InsertValue a e i []
+
+-- | See <https://llvm.org/docs/LangRef.html#icmp-instruction reference>.
+icmp :: MonadIRBuilder m => IP.IntegerPredicate -> Operand -> Operand -> m Operand
+icmp pred a b = emitInstr i1 $ ICmp pred a b []
+
+-- | See <https://llvm.org/docs/LangRef.html#fcmp-instruction reference>.
+fcmp :: MonadIRBuilder m => FP.FloatingPointPredicate -> Operand -> Operand -> m Operand
+fcmp pred a b = emitInstr i1 $ FCmp pred a b []
+
+-- | Unconditional branch.
+-- Emit a @br label <dest>@ instruction
+-- See <https://llvm.org/docs/LangRef.html#br-instruction reference>.
+br :: MonadIRBuilder m => Name -> m ()
+br val = emitTerm (Br val [])
+
+-- | See <https://llvm.org/docs/LangRef.html#phi-instruction reference>.
+phi :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => [(Operand, Name)] -> m Operand
+phi [] = emitInstr AST.void $ Phi AST.void [] []
+phi incoming@(i:_) = do
+  ty <- typeOf (fst i)
+  case ty of
+    (Left s) -> error s
+    (Right ty') -> emitInstr ty' $ Phi ty' incoming []
+
+-- | Emit a @ret void@ instruction.
+-- See <https://llvm.org/docs/LangRef.html#ret-instruction reference>.
+retVoid :: MonadIRBuilder m => m ()
+retVoid = emitTerm (Ret Nothing [])
+
+-- | See <https://llvm.org/docs/LangRef.html#call-instruction reference>.
+call :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> [(Operand, [ParameterAttribute])] -> m Operand
+call fun args = do
+  let instr = Call {
+    AST.tailCallKind = Nothing
+  , AST.callingConvention = CC.C
+  , AST.returnAttributes = []
+  , AST.function = Right fun
+  , AST.arguments = args
+  , AST.functionAttributes = []
+  , AST.metadata = []
+  }
+  tf <- typeOf fun
+  case tf of
+    (Left s) -> error s
+    (Right (FunctionType r _ _)) -> case r of
+      VoidType -> emitInstrVoid instr >> (pure (ConstantOperand (C.Undef void)))
+      _        -> emitInstr r instr
+    (Right (PointerType (FunctionType r _ _) _)) -> case r of
+      VoidType -> emitInstrVoid instr >> (pure (ConstantOperand (C.Undef void)))
+      _        -> emitInstr r instr
+    (Right _) -> error "Cannot call non-function (Malformed AST)."
+
+-- | See <https://llvm.org/docs/LangRef.html#ret-instruction reference>.
+ret :: MonadIRBuilder m => Operand -> m ()
+ret val = emitTerm (Ret (Just val) [])
+
+-- | See <https://llvm.org/docs/LangRef.html#switch-instruction reference>.
+switch :: MonadIRBuilder m => Operand -> Name -> [(C.Constant, Name)] -> m ()
+switch val def dests = emitTerm $ Switch val def dests []
+
+-- | See <https://llvm.org/docs/LangRef.html#select-instruction reference>.
+select :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Operand -> Operand -> Operand -> m Operand
+select cond t f = do
+  tt <- typeOf t
+  case tt of
+    (Left s) -> error s
+    (Right tt') -> emitInstr tt' $ Select cond t f []
+
+-- | Conditional branch (see 'br' for unconditional instructions).
+-- See <https://llvm.org/docs/LangRef.html#br-instruction reference>.
+condBr :: MonadIRBuilder m => Operand -> Name -> Name -> m ()
+condBr cond tdest fdest = emitTerm $ CondBr cond tdest fdest []
+
+-- | See <https://llvm.org/docs/LangRef.html#unreachable-instruction reference>.
+unreachable :: MonadIRBuilder m => m ()
+unreachable = emitTerm $ Unreachable []
+
+-- | Creates a series of instructions to generate a pointer to a string
+-- constant. Useful for making format strings to pass to @printf@, for example
+globalStringPtr
+  :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m)
+  => String       -- ^ The string to generate
+  -> Name         -- ^ Variable name of the pointer
+  -> m C.Constant
+globalStringPtr str nm = do
+  let asciiVals = map (fromIntegral . ord) str
+      llvmVals  = map (C.Int 8) (asciiVals ++ [0]) -- append null terminator
+      char      = IntegerType 8
+      charArray = C.Array char llvmVals
+  ty <- LLVM.AST.Typed.typeOf charArray
+  case ty of
+    (Left s) -> error s
+    (Right ty') -> do
+      emitDefn $ GlobalDefinition globalVariableDefaults
+        { name                  = nm
+        , LLVM.AST.Global.type' = ty'
+        , linkage               = External
+        , isConstant            = True
+        , initializer           = Just charArray
+        , unnamedAddr           = Just GlobalAddr
+        }
+      return $ C.GetElementPtr True
+                              (C.GlobalReference (ptr ty') nm)
+                              [(C.Int 32 0), (C.Int 32 0)]
+
+sizeof :: (HasCallStack, MonadIRBuilder m, MonadModuleBuilder m) => Word32 -> Type -> m Operand
+sizeof szBits ty = do
+  tyNullPtr <- inttoptr (ConstantOperand $ C.Int szBits 0) (ptr ty)
+  tySzPtr <- gep tyNullPtr [ConstantOperand $ C.Int szBits 1]
+  ptrtoint tySzPtr $ IntegerType szBits
diff --git a/src/LLVM/IRBuilder/Internal/SnocList.hs b/src/LLVM/IRBuilder/Internal/SnocList.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder/Internal/SnocList.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE CPP #-}
+module LLVM.IRBuilder.Internal.SnocList where
+
+import LLVM.Prelude
+
+newtype SnocList a = SnocList { unSnocList :: [a] }
+  deriving (Eq, Show)
+
+instance Semigroup (SnocList a) where
+  SnocList xs <> SnocList ys = SnocList $ ys ++ xs
+
+instance Monoid (SnocList a) where
+#if !(MIN_VERSION_base(4,11,0))
+  mappend = (<>)
+#endif
+  mempty = SnocList []
+
+snoc :: SnocList a -> a -> SnocList a
+snoc (SnocList xs) x = SnocList $ x : xs
+
+getSnocList :: SnocList a -> [a]
+getSnocList = reverse . unSnocList
diff --git a/src/LLVM/IRBuilder/Module.hs b/src/LLVM/IRBuilder/Module.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder/Module.hs
@@ -0,0 +1,248 @@
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DefaultSignatures          #-}
+{-# LANGUAGE DeriveDataTypeable         #-}
+{-# LANGUAGE DeriveGeneric              #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE UndecidableInstances       #-} -- For MonadState s (IRBuilderT m) instance
+
+module LLVM.IRBuilder.Module where
+
+import Prelude hiding (and, or)
+
+import Control.Applicative
+import Control.Monad.Cont
+import Control.Monad.Except
+import qualified Control.Monad.Fail as Fail
+import Control.Monad.Identity
+import Control.Monad.Writer.Lazy as Lazy
+import Control.Monad.Writer.Strict as Strict
+import Control.Monad.Reader
+import Control.Monad.RWS.Lazy as Lazy
+import Control.Monad.RWS.Strict as Strict
+import qualified Control.Monad.State.Strict as Strict
+import Control.Monad.State.Lazy
+import Control.Monad.Trans.Maybe
+#if !(MIN_VERSION_mtl(2,2,2))
+import Control.Monad.Trans.Identity
+#endif
+#if __GLASGOW_HASKELL__ < 808
+import Control.Monad.Fail (MonadFail)
+#endif
+
+import Data.Bifunctor
+import qualified Data.ByteString.Short as BS
+import Data.ByteString.Short(ShortByteString)
+import Data.Char
+import Data.Data
+import Data.Foldable
+import Data.Map.Lazy (Map)
+import qualified Data.Map.Lazy as Map
+import Data.String
+
+import GHC.Generics(Generic)
+
+import LLVM.AST hiding (function)
+import LLVM.AST.Global
+import LLVM.AST.Linkage
+import LLVM.AST.Type (ptr)
+import qualified LLVM.AST.Constant as C
+
+import LLVM.IRBuilder.Internal.SnocList
+import LLVM.IRBuilder.Monad
+
+newtype ModuleBuilderT m a = ModuleBuilderT { unModuleBuilderT :: StateT ModuleBuilderState m a }
+  deriving
+    ( Functor, Alternative, Applicative, Monad, MonadCont, MonadError e
+    , MonadFix, MonadIO, MonadPlus, MonadReader r, MonadTrans, MonadWriter w
+    )
+
+instance MonadFail m => MonadFail (ModuleBuilderT m) where
+  fail str = ModuleBuilderT (StateT $ \_ -> Fail.fail str)
+
+data ModuleBuilderState = ModuleBuilderState
+  { builderDefs :: SnocList Definition
+  , builderTypeDefs :: Map Name Type
+  }
+
+emptyModuleBuilder :: ModuleBuilderState
+emptyModuleBuilder = ModuleBuilderState
+  { builderDefs = mempty
+  , builderTypeDefs = mempty
+  }
+
+type ModuleBuilder = ModuleBuilderT Identity
+
+class Monad m => MonadModuleBuilder m where
+  liftModuleState :: State ModuleBuilderState a -> m a
+
+  default liftModuleState
+    :: (MonadTrans t, MonadModuleBuilder m1, m ~ t m1)
+    => State ModuleBuilderState a
+    -> m a
+  liftModuleState = lift . liftModuleState
+
+instance Monad m => MonadModuleBuilder (ModuleBuilderT m) where
+  liftModuleState (StateT s) = ModuleBuilderT $ StateT $ pure . runIdentity . s
+
+
+
+-- | Evaluate 'ModuleBuilder' to a result and a list of definitions
+runModuleBuilder :: ModuleBuilderState -> ModuleBuilder a -> (a, [Definition])
+runModuleBuilder s m = runIdentity $ runModuleBuilderT s m
+
+-- | Evaluate 'ModuleBuilderT' to a result and a list of definitions
+runModuleBuilderT :: Monad m => ModuleBuilderState -> ModuleBuilderT m a -> m (a, [Definition])
+runModuleBuilderT s (ModuleBuilderT m)
+  = second (getSnocList . builderDefs)
+  <$> runStateT m s
+
+-- | Evaluate 'ModuleBuilder' to a list of definitions
+execModuleBuilder :: ModuleBuilderState -> ModuleBuilder a -> [Definition]
+execModuleBuilder s m = snd $ runModuleBuilder s m
+
+-- | Evaluate 'ModuleBuilderT' to a list of definitions
+execModuleBuilderT :: Monad m => ModuleBuilderState -> ModuleBuilderT m a -> m [Definition]
+execModuleBuilderT s m = snd <$> runModuleBuilderT s m
+
+emitDefn :: MonadModuleBuilder m => Definition -> m ()
+emitDefn def = liftModuleState $ modify $ \s -> s { builderDefs = builderDefs s `snoc` def }
+
+-- | A parameter name suggestion
+data ParameterName
+  = NoParameterName
+  | ParameterName ShortByteString
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Using 'fromString` on non-ASCII strings will throw an error.
+instance IsString ParameterName where
+  fromString s
+    | all isAscii s = ParameterName (fromString s)
+    | otherwise =
+      error ("Only ASCII strings are automatically converted to LLVM parameter names. "
+      <> "Other strings need to be encoded to a `ShortByteString` using an arbitrary encoding.")
+
+-- | Define and emit a (non-variadic) function definition
+function
+  :: MonadModuleBuilder m
+  => Name  -- ^ Function name
+  -> [(Type, ParameterName)]  -- ^ Parameter types and name suggestions
+  -> Type  -- ^ Return type
+  -> ([Operand] -> IRBuilderT m ())  -- ^ Function body builder
+  -> m Operand
+function label argtys retty body = do
+  let tys = fst <$> argtys
+  (paramNames, blocks) <- runIRBuilderT emptyIRBuilder $ do
+    paramNames <- forM argtys $ \(_, paramName) -> case paramName of
+      NoParameterName -> fresh
+      ParameterName p -> fresh `named` p
+    body $ zipWith LocalReference tys paramNames
+    return paramNames
+  let
+    def = GlobalDefinition functionDefaults
+      { name        = label
+      , parameters  = (zipWith (\ty nm -> Parameter ty nm []) tys paramNames, False)
+      , returnType  = retty
+      , basicBlocks = blocks
+      }
+    funty = ptr $ FunctionType retty (fst <$> argtys) False
+  emitDefn def
+  pure $ ConstantOperand $ C.GlobalReference funty label
+
+-- | An external function definition
+extern
+  :: MonadModuleBuilder m
+  => Name   -- ^ Definition name
+  -> [Type] -- ^ Parameter types
+  -> Type   -- ^ Type
+  -> m Operand
+extern nm argtys retty = do
+  emitDefn $ GlobalDefinition functionDefaults
+    { name        = nm
+    , linkage     = External
+    , parameters  = ([Parameter ty (mkName "") [] | ty <- argtys], False)
+    , returnType  = retty
+    }
+  let funty = ptr $ FunctionType retty argtys False
+  pure $ ConstantOperand $ C.GlobalReference funty nm
+
+-- | An external variadic argument function definition
+externVarArgs
+  :: MonadModuleBuilder m
+  => Name   -- ^ Definition name
+  -> [Type] -- ^ Parameter types
+  -> Type   -- ^ Type
+  -> m Operand
+externVarArgs nm argtys retty = do
+  emitDefn $ GlobalDefinition functionDefaults
+    { name        = nm
+    , linkage     = External
+    , parameters  = ([Parameter ty (mkName "") [] | ty <- argtys], True)
+    , returnType  = retty
+    }
+  let funty = ptr $ FunctionType retty argtys True
+  pure $ ConstantOperand $ C.GlobalReference funty nm
+
+-- | A global variable definition
+global
+  :: MonadModuleBuilder m
+  => Name       -- ^ Variable name
+  -> Type       -- ^ Type
+  -> C.Constant -- ^ Initializer
+  -> m Operand
+global nm ty initVal = do
+  emitDefn $ GlobalDefinition globalVariableDefaults
+    { name                  = nm
+    , LLVM.AST.Global.type' = ty
+    , linkage               = External
+    , initializer           = Just initVal
+    }
+  pure $ ConstantOperand $ C.GlobalReference (ptr ty) nm
+
+-- | A named type definition
+typedef
+  :: MonadModuleBuilder m
+  => Name
+  -> Maybe Type
+  -> m Type
+typedef nm ty = do
+  emitDefn $ TypeDefinition nm ty
+  for_ ty $ \ty' ->
+    liftModuleState (modify (\s -> s { builderTypeDefs = Map.insert nm ty' (builderTypeDefs s) }))
+  pure (NamedTypeReference nm)
+
+-- | Convenience function for module construction
+buildModule :: ShortByteString -> ModuleBuilder a -> Module
+buildModule nm = mkModule . execModuleBuilder emptyModuleBuilder
+  where
+    mkModule ds = defaultModule { moduleName = nm, moduleDefinitions = ds }
+
+-- | Convenience function for module construction (transformer version)
+buildModuleT :: Monad m => ShortByteString -> ModuleBuilderT m a -> m Module
+buildModuleT nm = fmap mkModule . execModuleBuilderT emptyModuleBuilder
+  where
+    mkModule ds = defaultModule { moduleName = nm, moduleDefinitions = ds }
+
+-------------------------------------------------------------------------------
+-- mtl instances
+-------------------------------------------------------------------------------
+
+instance MonadState s m => MonadState s (ModuleBuilderT m) where
+  state = lift . state
+
+instance MonadModuleBuilder m => MonadModuleBuilder (ContT r m)
+instance MonadModuleBuilder m => MonadModuleBuilder (ExceptT e m)
+instance MonadModuleBuilder m => MonadModuleBuilder (IdentityT m)
+instance MonadModuleBuilder m => MonadModuleBuilder (MaybeT m)
+instance MonadModuleBuilder m => MonadModuleBuilder (ReaderT r m)
+instance (MonadModuleBuilder m, Monoid w) => MonadModuleBuilder (Strict.RWST r w s m)
+instance (MonadModuleBuilder m, Monoid w) => MonadModuleBuilder (Lazy.RWST r w s m)
+instance MonadModuleBuilder m => MonadModuleBuilder (StateT s m)
+instance MonadModuleBuilder m => MonadModuleBuilder (Strict.StateT s m)
+instance (Monoid w, MonadModuleBuilder m) => MonadModuleBuilder (Strict.WriterT w m)
+
+-- Not an mtl instance, but necessary in order for @globalStringPtr@ to compile
+instance MonadModuleBuilder m => MonadModuleBuilder (IRBuilderT m)
diff --git a/src/LLVM/IRBuilder/Monad.hs b/src/LLVM/IRBuilder/Monad.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/IRBuilder/Monad.hs
@@ -0,0 +1,298 @@
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE DefaultSignatures          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE UndecidableInstances       #-} -- For MonadState s (ModuleBuilderT m) instance
+
+module LLVM.IRBuilder.Monad where
+
+import LLVM.Prelude
+
+import Control.Monad.Cont
+import Control.Monad.Except
+import qualified Control.Monad.Fail as Fail
+import Control.Monad.Identity
+import qualified Control.Monad.Writer.Lazy as Lazy
+import qualified Control.Monad.Writer.Strict as Strict
+import Control.Monad.Writer (MonadWriter)
+import Control.Monad.Reader
+import qualified Control.Monad.RWS.Lazy as Lazy
+import qualified Control.Monad.RWS.Strict as Strict
+import qualified Control.Monad.State.Lazy as Lazy
+import Control.Monad.State.Strict
+import Control.Monad.Trans.Maybe
+#if !(MIN_VERSION_mtl(2,2,2))
+import Control.Monad.Trans.Identity
+#endif
+#if __GLASGOW_HASKELL__ < 808
+import Control.Monad.Fail (MonadFail)
+#endif
+
+import Data.Bifunctor
+import Data.Monoid (First(..))
+import Data.String
+import Data.Map.Strict(Map)
+import qualified Data.Map.Strict as M
+import GHC.Stack
+
+import LLVM.AST
+
+import LLVM.IRBuilder.Internal.SnocList
+
+-- | This provides a uniform API for creating instructions and inserting them
+-- into a basic block: either at the end of a BasicBlock, or at a specific
+-- location in a block.
+newtype IRBuilderT m a = IRBuilderT { unIRBuilderT :: StateT IRBuilderState m a }
+  deriving
+    ( Functor, Alternative, Applicative, Monad, MonadCont, MonadError e
+    , MonadFix, MonadIO, MonadPlus, MonadReader r, MonadTrans, MonadWriter w
+    )
+
+instance MonadFail m => MonadFail (IRBuilderT m) where
+    fail str = IRBuilderT (StateT $ \ _ -> Fail.fail str)
+
+type IRBuilder = IRBuilderT Identity
+
+class Monad m => MonadIRBuilder m where
+  liftIRState :: State IRBuilderState a -> m a
+
+  default liftIRState
+    :: (MonadTrans t, MonadIRBuilder m1, m ~ t m1)
+    => State IRBuilderState a
+    -> m a
+  liftIRState = lift . liftIRState
+
+instance Monad m => MonadIRBuilder (IRBuilderT m) where
+  liftIRState (StateT s) = IRBuilderT $ StateT $ pure . runIdentity . s
+
+-- | A partially constructed block as a sequence of instructions
+data PartialBlock = PartialBlock
+  { partialBlockName :: !Name
+  , partialBlockInstrs :: SnocList (Named Instruction)
+  , partialBlockTerm :: First (Named Terminator)
+  }
+
+emptyPartialBlock :: Name -> PartialBlock
+emptyPartialBlock nm = PartialBlock nm mempty (First Nothing)
+
+-- | Builder monad state
+data IRBuilderState = IRBuilderState
+  { builderSupply :: !Word
+  , builderUsedNames :: !(Map ShortByteString Word)
+  , builderNameSuggestion :: !(Maybe ShortByteString)
+  , builderBlocks :: SnocList BasicBlock
+  , builderBlock :: !(Maybe PartialBlock)
+  }
+
+emptyIRBuilder :: IRBuilderState
+emptyIRBuilder = IRBuilderState
+  { builderSupply = 0
+  , builderUsedNames = mempty
+  , builderNameSuggestion = Nothing
+  , builderBlocks = mempty
+  , builderBlock = Nothing
+  }
+
+-- | Evaluate IRBuilder to a result and a list of basic blocks
+runIRBuilder :: IRBuilderState -> IRBuilder a -> (a, [BasicBlock])
+runIRBuilder s m = runIdentity $ runIRBuilderT s m
+
+-- | Evaluate IRBuilderT to a result and a list of basic blocks
+runIRBuilderT :: Monad m => IRBuilderState -> IRBuilderT m a -> m (a, [BasicBlock])
+runIRBuilderT s m
+  = second (getSnocList . builderBlocks)
+  <$> runStateT (unIRBuilderT $ m <* block) s
+
+-- | Evaluate IRBuilder to a list of basic blocks
+execIRBuilder :: IRBuilderState -> IRBuilder a -> [BasicBlock]
+execIRBuilder s m = snd $ runIRBuilder s m
+
+-- | Evaluate IRBuilderT to a list of basic blocks
+execIRBuilderT :: Monad m => IRBuilderState -> IRBuilderT m a -> m [BasicBlock]
+execIRBuilderT s m = snd <$> runIRBuilderT s m
+
+-------------------------------------------------------------------------------
+-- * Low-level functionality
+-------------------------------------------------------------------------------
+
+-- | If no partial block exists, create a new block with a fresh label.
+--
+-- This is useful if you want to ensure that the label for the block
+-- is assigned before another label which is not possible with
+-- `modifyBlock`.
+ensureBlock :: MonadIRBuilder m => m ()
+ensureBlock = do
+  mbb <- liftIRState $ gets builderBlock
+  case mbb of
+    Nothing -> do
+      nm <- freshUnName
+      liftIRState $ modify $ \s -> s { builderBlock = Just $! emptyPartialBlock nm }
+    Just _ -> pure ()
+
+modifyBlock
+  :: MonadIRBuilder m
+  => (PartialBlock -> PartialBlock)
+  -> m ()
+modifyBlock f = do
+  mbb <- liftIRState $ gets builderBlock
+  case mbb of
+    Nothing -> do
+      nm <- freshUnName
+      liftIRState $ modify $ \s -> s { builderBlock = Just $! f $ emptyPartialBlock nm }
+    Just bb ->
+      liftIRState $ modify $ \s -> s { builderBlock = Just $! f bb }
+
+-- | Generate a fresh name. The resulting name is numbered or
+-- based on the name suggested with 'named' if that's used.
+fresh :: MonadIRBuilder m => m Name
+fresh = do
+  msuggestion <- liftIRState $ gets builderNameSuggestion
+  maybe freshUnName freshName msuggestion
+
+-- | Generate a fresh name from a name suggestion
+freshName :: MonadIRBuilder m => ShortByteString -> m Name
+freshName suggestion = do
+  usedNames <- liftIRState $ gets builderUsedNames
+  let
+    nameCount = fromMaybe 0 $ M.lookup suggestion usedNames
+    unusedName = suggestion <> fromString ("_" <> show nameCount)
+    updatedUsedNames = M.insert suggestion (nameCount + 1) usedNames
+  liftIRState $ modify $ \s -> s { builderUsedNames = updatedUsedNames }
+  return $ Name unusedName
+
+-- | Generate a fresh numbered name
+freshUnName :: MonadIRBuilder m => m Name
+freshUnName = liftIRState $ do
+  n <- gets builderSupply
+  modify $ \s -> s { builderSupply = 1 + n }
+  pure $ UnName n
+
+-- | Emit instruction
+emitInstr
+  :: MonadIRBuilder m
+  => Type -- ^ Return type
+  -> Instruction
+  -> m Operand
+emitInstr retty instr = do
+  -- Ensure that the fresh identifier for the block is assigned before the identifier for the instruction.
+  ensureBlock
+  nm <- fresh
+  modifyBlock $ \bb -> bb
+    { partialBlockInstrs = partialBlockInstrs bb `snoc` (nm := instr)
+    }
+  pure (LocalReference retty nm)
+
+-- | Emit instruction that returns void
+emitInstrVoid
+  :: MonadIRBuilder m
+  => Instruction
+  -> m ()
+emitInstrVoid instr = do
+  modifyBlock $ \bb -> bb
+    { partialBlockInstrs = partialBlockInstrs bb `snoc` (Do instr)
+    }
+  pure ()
+
+-- | Emit terminator
+emitTerm
+  :: MonadIRBuilder m
+  => Terminator
+  -> m ()
+emitTerm term = modifyBlock $ \bb -> bb
+  { partialBlockTerm = partialBlockTerm bb <> First (Just (Do term))
+  }
+
+-- | Starts a new block labelled using the given name and ends the previous
+-- one. The name is assumed to be fresh.
+emitBlockStart
+  :: MonadIRBuilder m
+  => Name
+  -> m ()
+emitBlockStart nm = do
+  mbb <- liftIRState $ gets builderBlock
+  case mbb of
+    Nothing -> return ()
+    Just bb -> do
+      let
+        instrs = getSnocList $ partialBlockInstrs bb
+        newBb = case getFirst (partialBlockTerm bb) of
+          Nothing   -> BasicBlock (partialBlockName bb) instrs (Do (Ret Nothing []))
+          Just term -> BasicBlock (partialBlockName bb) instrs term
+      liftIRState $ modify $ \s -> s
+        { builderBlocks = builderBlocks s `snoc` newBb
+        }
+  liftIRState $ modify $ \s -> s { builderBlock = Just $ emptyPartialBlock nm }
+
+-------------------------------------------------------------------------------
+-- * High-level functionality
+-------------------------------------------------------------------------------
+
+-- | Starts a new block and ends the previous one
+block
+  :: MonadIRBuilder m
+  => m Name
+block = do
+  nm <- fresh
+  emitBlockStart nm
+  return nm
+
+-- | @ir `named` name@ executes the 'IRBuilder' @ir@ using @name@ as the base
+-- name whenever a fresh local name is generated. Collisions are avoided by
+-- appending numbers (first @"name"@, then @"name1"@, @"name2"@, and so on).
+named
+  :: MonadIRBuilder m
+  => m r
+  -> ShortByteString
+  -> m r
+named ir name = do
+  before <- liftIRState $ gets builderNameSuggestion
+  liftIRState $ modify $ \s -> s { builderNameSuggestion = Just name }
+  result <- ir
+  liftIRState $ modify $ \s -> s { builderNameSuggestion = before }
+  return result
+
+-- | Get the name of the currently active block.
+--
+-- This function will throw an error if there is no active block. The
+-- only situation in which this can occur is if it is called before
+-- any call to `block` and before emitting any instructions.
+currentBlock :: HasCallStack => MonadIRBuilder m => m Name
+currentBlock = liftIRState $ do
+  name <- gets (fmap partialBlockName . builderBlock)
+  case name of
+    Just n -> pure n
+    Nothing -> error "Called currentBlock when no block was active"
+
+-- | Find out if the currently active block has a terminator.
+--
+-- This function will fail under the same condition as @currentBlock@
+hasTerminator :: HasCallStack => MonadIRBuilder m => m Bool
+hasTerminator = do
+  current <- liftIRState $ gets builderBlock
+  case current of
+    Nothing    -> error "Called hasTerminator when no block was active"
+    Just blk -> case getFirst (partialBlockTerm blk) of
+      Nothing  -> return False
+      Just _   -> return True
+
+-------------------------------------------------------------------------------
+-- mtl instances
+-------------------------------------------------------------------------------
+
+instance MonadState s m => MonadState s (IRBuilderT m) where
+  state = lift . state
+
+instance MonadIRBuilder m => MonadIRBuilder (ContT r m)
+instance MonadIRBuilder m => MonadIRBuilder (ExceptT e m)
+instance MonadIRBuilder m => MonadIRBuilder (IdentityT m)
+instance MonadIRBuilder m => MonadIRBuilder (MaybeT m)
+instance MonadIRBuilder m => MonadIRBuilder (ReaderT r m)
+instance (MonadIRBuilder m, Monoid w) => MonadIRBuilder (Strict.RWST r w s m)
+instance (MonadIRBuilder m, Monoid w) => MonadIRBuilder (Lazy.RWST r w s m)
+instance MonadIRBuilder m => MonadIRBuilder (StateT s m)
+instance MonadIRBuilder m => MonadIRBuilder (Lazy.StateT s m)
+instance (Monoid w, MonadIRBuilder m) => MonadIRBuilder (Strict.WriterT w m)
+instance (Monoid w, MonadIRBuilder m) => MonadIRBuilder (Lazy.WriterT w m)
diff --git a/src/LLVM/Internal/Analysis.hs b/src/LLVM/Internal/Analysis.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Analysis.hs
@@ -0,0 +1,24 @@
+module LLVM.Internal.Analysis where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+
+import qualified LLVM.Internal.FFI.Analysis as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Module
+import LLVM.Internal.Coding
+
+import LLVM.Exception
+
+-- | Run basic sanity checks on a 'Module'. Note that the same checks will trigger assertions
+-- within LLVM if LLVM was built with them turned on, before this function can be is called.
+verify :: Module -> IO ()
+verify m = runAnyContT' return $ do
+  errorPtr <- alloca
+  m' <- readModule m
+  result <- decodeM =<< (liftIO $ FFI.verifyModule m' FFI.verifierFailureActionReturnStatus errorPtr)
+  when result $ throwM . VerifyException =<< decodeM errorPtr
diff --git a/src/LLVM/Internal/Atomicity.hs b/src/LLVM/Internal/Atomicity.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Atomicity.hs
@@ -0,0 +1,49 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.Atomicity where
+
+import LLVM.Prelude
+
+import Data.Maybe
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Coding
+import qualified LLVM.AST as A
+
+genCodingInstance [t| Maybe A.MemoryOrdering |] ''FFI.MemoryOrdering [
+  (FFI.memoryOrderingNotAtomic, Nothing),
+  (FFI.memoryOrderingUnordered, Just A.Unordered),
+  (FFI.memoryOrderingMonotonic, Just A.Monotonic),
+  (FFI.memoryOrderingAcquire, Just A.Acquire),
+  (FFI.memoryOrderingRelease, Just A.Release),
+  (FFI.memoryOrderingAcquireRelease, Just A.AcquireRelease),
+  (FFI.memoryOrderingSequentiallyConsistent, Just A.SequentiallyConsistent)
+ ]
+
+genCodingInstance [t| A.SynchronizationScope |] ''FFI.SynchronizationScope [
+  (FFI.synchronizationScopeSingleThread, A.SingleThread),
+  (FFI.synchronizationScopeSystem, A.System)
+ ]
+
+instance Monad m => EncodeM m (Maybe A.Atomicity) (FFI.SynchronizationScope, FFI.MemoryOrdering) where
+  encodeM a =
+    return (,) `ap` encodeM (maybe A.SingleThread fst a) `ap` encodeM (liftM snd a)
+
+instance Monad m => DecodeM m (Maybe A.Atomicity) (FFI.SynchronizationScope, FFI.MemoryOrdering) where
+  decodeM (ss, ao) = return (liftM . (,)) `ap` decodeM ss `ap` decodeM ao
+
+instance Monad m => EncodeM m A.Atomicity (FFI.SynchronizationScope, FFI.MemoryOrdering) where
+  encodeM = encodeM . Just
+
+instance Monad m => DecodeM m A.Atomicity (FFI.SynchronizationScope, FFI.MemoryOrdering) where
+  decodeM = liftM fromJust . decodeM
+
+instance Monad m => EncodeM m A.MemoryOrdering FFI.MemoryOrdering where
+  encodeM = encodeM . Just
+
+instance Monad m => DecodeM m A.MemoryOrdering FFI.MemoryOrdering where
+  decodeM = liftM fromJust . decodeM
+
diff --git a/src/LLVM/Internal/Attribute.hs b/src/LLVM/Internal/Attribute.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Attribute.hs
@@ -0,0 +1,328 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE ConstraintKinds       #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE QuasiQuotes           #-}
+{-# LANGUAGE RankNTypes            #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE UndecidableInstances  #-}
+
+module LLVM.Internal.Attribute where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+import Control.Monad.State (gets)
+
+import Control.Exception
+import Foreign.C (CUInt)
+import Foreign.Ptr
+import Data.Maybe
+
+import qualified LLVM.Internal.FFI.Attribute as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import LLVM.Internal.FFI.LLVMCTypes (parameterAttributeKindP, functionAttributeKindP)
+
+import qualified LLVM.AST.ParameterAttribute as A.PA
+import qualified LLVM.AST.FunctionAttribute as A.FA
+
+import LLVM.Internal.Coding
+import LLVM.Internal.Context
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.DecodeAST
+
+inconsistentCases :: Show a => String -> a -> b
+inconsistentCases name attr =
+  error $ "llvm-hs internal error: cases inconstistent in " ++ name ++ " encoding for " ++ show attr
+
+instance Monad m => EncodeM m A.PA.ParameterAttribute (Ptr FFI.ParameterAttrBuilder -> EncodeAST ()) where
+  encodeM (A.PA.StringAttribute kind value) = return $ \b -> do
+    (kindP, kindLen) <- encodeM kind
+    (valueP, valueLen) <- encodeM value
+    liftIO $ FFI.attrBuilderAddStringAttribute b kindP kindLen valueP valueLen
+  encodeM a = return $ \b -> liftIO $ case a of
+    A.PA.Alignment v -> FFI.attrBuilderAddAlignment b v
+    A.PA.Dereferenceable v -> FFI.attrBuilderAddDereferenceable b v
+    A.PA.DereferenceableOrNull v -> FFI.attrBuilderAddDereferenceableOrNull b v
+    _ -> FFI.attrBuilderAddParameterAttributeKind b $ case a of
+      A.PA.ByVal -> FFI.parameterAttributeKindByVal
+      A.PA.ImmArg -> FFI.parameterAttributeKindImmArg
+      A.PA.InAlloca -> FFI.parameterAttributeKindInAlloca
+      A.PA.InReg -> FFI.parameterAttributeKindInReg
+      A.PA.Nest -> FFI.parameterAttributeKindNest
+      A.PA.NoAlias -> FFI.parameterAttributeKindNoAlias
+      A.PA.NoCapture -> FFI.parameterAttributeKindNoCapture
+      A.PA.NoFree -> FFI.parameterAttributeKindNoFree
+      A.PA.NonNull -> FFI.parameterAttributeKindNonNull
+      A.PA.ReadNone -> FFI.parameterAttributeKindReadNone
+      A.PA.ReadOnly -> FFI.parameterAttributeKindReadOnly
+      A.PA.Returned -> FFI.parameterAttributeKindReturned
+      A.PA.SignExt -> FFI.parameterAttributeKindSExt
+      A.PA.SRet -> FFI.parameterAttributeKindStructRet
+      A.PA.SwiftError -> FFI.parameterAttributeKindSwiftError
+      A.PA.SwiftSelf -> FFI.parameterAttributeKindSwiftSelf
+      A.PA.WriteOnly -> FFI.parameterAttributeKindWriteOnly
+      A.PA.ZeroExt -> FFI.parameterAttributeKindZExt
+#if __GLASGOW_HASKELL__ < 900
+      A.PA.Alignment _ -> inconsistentCases "ParameterAttribute" a
+      A.PA.Dereferenceable _ -> inconsistentCases "ParameterAttribute" a
+      A.PA.DereferenceableOrNull _ -> inconsistentCases "ParameterAttribute" a
+      A.PA.StringAttribute _ _ -> inconsistentCases "ParameterAttribute" a
+#endif
+
+instance Monad m => EncodeM m A.FA.FunctionAttribute (Ptr FFI.FunctionAttrBuilder -> EncodeAST ()) where
+  encodeM (A.FA.StringAttribute kind value) = return $ \b -> do
+    (kindP, kindLen) <- encodeM kind
+    (valueP, valueLen) <- encodeM value
+    liftIO $ FFI.attrBuilderAddStringAttribute b kindP kindLen valueP valueLen
+  encodeM a = return $ \b -> case a of
+    A.FA.AllocSize x y -> do
+      x' <- encodeM x
+      y' <- encodeM y
+      liftIO $ FFI.attrBuilderAddAllocSize b x' y'
+    A.FA.StackAlignment v -> liftIO $ FFI.attrBuilderAddStackAlignment b v
+    _ -> liftIO $ FFI.attrBuilderAddFunctionAttributeKind b $ case a of
+      A.FA.AlwaysInline -> FFI.functionAttributeKindAlwaysInline
+      A.FA.ArgMemOnly -> FFI.functionAttributeKindArgMemOnly
+      A.FA.Builtin -> FFI.functionAttributeKindBuiltin
+      A.FA.Cold -> FFI.functionAttributeKindCold
+      A.FA.Convergent -> FFI.functionAttributeKindConvergent
+      A.FA.InaccessibleMemOnly -> FFI.functionAttributeKindInaccessibleMemOnly
+      A.FA.InaccessibleMemOrArgMemOnly -> FFI.functionAttributeKindInaccessibleMemOrArgMemOnly
+      A.FA.InlineHint -> FFI.functionAttributeKindInlineHint
+      A.FA.JumpTable -> FFI.functionAttributeKindJumpTable
+      A.FA.MinimizeSize -> FFI.functionAttributeKindMinSize
+      A.FA.MustProgress -> FFI.functionAttributeKindMustProgress
+      A.FA.Naked -> FFI.functionAttributeKindNaked
+      A.FA.NoBuiltin -> FFI.functionAttributeKindNoBuiltin
+      A.FA.NoDuplicate -> FFI.functionAttributeKindNoDuplicate
+      A.FA.NoFree -> FFI.functionAttributeKindNoFree
+      A.FA.NoImplicitFloat -> FFI.functionAttributeKindNoImplicitFloat
+      A.FA.NoInline -> FFI.functionAttributeKindNoInline
+      A.FA.NonLazyBind -> FFI.functionAttributeKindNonLazyBind
+      A.FA.NoRecurse -> FFI.functionAttributeKindNoRecurse
+      A.FA.NoRedZone -> FFI.functionAttributeKindNoRedZone
+      A.FA.NoReturn -> FFI.functionAttributeKindNoReturn
+      A.FA.NoSync -> FFI.functionAttributeKindNoSync
+      A.FA.NoUnwind -> FFI.functionAttributeKindNoUnwind
+      A.FA.OptimizeForSize -> FFI.functionAttributeKindOptimizeForSize
+      A.FA.OptimizeNone -> FFI.functionAttributeKindOptimizeNone
+      A.FA.ReadNone -> FFI.functionAttributeKindReadNone
+      A.FA.ReadOnly -> FFI.functionAttributeKindReadOnly
+      A.FA.ReturnsTwice -> FFI.functionAttributeKindReturnsTwice
+      A.FA.SafeStack -> FFI.functionAttributeKindSafeStack
+      A.FA.SanitizeAddress -> FFI.functionAttributeKindSanitizeAddress
+      A.FA.SanitizeHWAddress -> FFI.functionAttributeKindSanitizeHWAddress
+      A.FA.SanitizeMemory -> FFI.functionAttributeKindSanitizeMemory
+      A.FA.SanitizeThread -> FFI.functionAttributeKindSanitizeThread
+      A.FA.Speculatable -> FFI.functionAttributeKindSpeculatable
+      A.FA.StackProtect -> FFI.functionAttributeKindStackProtect
+      A.FA.StackProtectReq -> FFI.functionAttributeKindStackProtectReq
+      A.FA.StackProtectStrong -> FFI.functionAttributeKindStackProtectStrong
+      A.FA.StrictFP -> FFI.functionAttributeKindStrictFP
+      A.FA.UWTable -> FFI.functionAttributeKindUWTable
+      A.FA.WillReturn -> FFI.functionAttributeKindWillReturn
+      A.FA.WriteOnly -> FFI.functionAttributeKindWriteOnly
+#if __GLASGOW_HASKELL__ < 900
+      A.FA.AllocSize _ _ -> inconsistentCases "FunctionAttribute" a
+      A.FA.StackAlignment _ -> inconsistentCases "FunctionAttribute" a
+      A.FA.StringAttribute _ _ -> inconsistentCases "FunctionAttribute" a
+#endif
+
+instance DecodeM DecodeAST A.PA.ParameterAttribute FFI.ParameterAttribute where
+  decodeM a = do
+    isString <- decodeM =<< liftIO (FFI.isStringAttribute a)
+    if isString
+      then
+        A.PA.StringAttribute
+          <$> decodeM (FFI.attributeKindAsString a)
+          <*> decodeM (FFI.attributeValueAsString a)
+      else do
+        enum <- liftIO $ FFI.parameterAttributeKindAsEnum a
+        case enum of
+          [parameterAttributeKindP|Alignment|] -> return A.PA.Alignment `ap` (liftIO $ FFI.attributeValueAsInt a)
+          [parameterAttributeKindP|ByVal|] -> return A.PA.ByVal
+          [parameterAttributeKindP|DereferenceableOrNull|] -> return A.PA.DereferenceableOrNull `ap` (liftIO $ FFI.attributeValueAsInt a)
+          [parameterAttributeKindP|Dereferenceable|] -> return A.PA.Dereferenceable `ap` (liftIO $ FFI.attributeValueAsInt a)
+          [parameterAttributeKindP|ImmArg|] -> return A.PA.ImmArg
+          [parameterAttributeKindP|InAlloca|] -> return A.PA.InAlloca
+          [parameterAttributeKindP|InReg|] -> return A.PA.InReg
+          [parameterAttributeKindP|Nest|] -> return A.PA.Nest
+          [parameterAttributeKindP|NoAlias|] -> return A.PA.NoAlias
+          [parameterAttributeKindP|NoCapture|] -> return A.PA.NoCapture
+          [parameterAttributeKindP|NoFree|] -> return A.PA.NoFree
+          [parameterAttributeKindP|NonNull|] -> return A.PA.NonNull
+          [parameterAttributeKindP|ReadNone|] -> return A.PA.ReadNone
+          [parameterAttributeKindP|ReadOnly|] -> return A.PA.ReadOnly
+          [parameterAttributeKindP|Returned|] -> return A.PA.Returned
+          [parameterAttributeKindP|SExt|] -> return A.PA.SignExt
+          [parameterAttributeKindP|StructRet|] -> return A.PA.SRet
+          [parameterAttributeKindP|SwiftError|] -> return A.PA.SwiftError
+          [parameterAttributeKindP|SwiftSelf|] -> return A.PA.SwiftSelf
+          [parameterAttributeKindP|WriteOnly|] -> return A.PA.WriteOnly
+          [parameterAttributeKindP|ZExt|] -> return A.PA.ZeroExt
+          _ -> error $ "unhandled parameter attribute enum value: " ++ show enum
+
+instance DecodeM DecodeAST A.FA.FunctionAttribute FFI.FunctionAttribute where
+  decodeM a = do
+    isString <- decodeM =<< (liftIO $ FFI.isStringAttribute a)
+    if isString
+       then
+         return A.FA.StringAttribute
+                  `ap` (decodeM $ FFI.attributeKindAsString a)
+                  `ap` (decodeM $ FFI.attributeValueAsString a)
+       else do
+         enum <- liftIO $ FFI.functionAttributeKindAsEnum a
+         case enum of
+           [functionAttributeKindP|AllocSize|] -> do
+             x <- alloca
+             y <- decodeOptional (FFI.attributeGetAllocSizeArgs a x)
+             x' <- decodeM =<< peek x
+             return (A.FA.AllocSize x' y)
+           [functionAttributeKindP|AlwaysInline|] -> return A.FA.AlwaysInline
+           [functionAttributeKindP|ArgMemOnly|] -> return A.FA.ArgMemOnly
+           [functionAttributeKindP|Builtin|] -> return A.FA.Builtin
+           [functionAttributeKindP|Cold|] -> return A.FA.Cold
+           [functionAttributeKindP|Convergent|] -> return A.FA.Convergent
+           [functionAttributeKindP|InaccessibleMemOnly|] -> return A.FA.InaccessibleMemOnly
+           [functionAttributeKindP|InaccessibleMemOrArgMemOnly|] -> return A.FA.InaccessibleMemOrArgMemOnly
+           [functionAttributeKindP|InlineHint|] -> return A.FA.InlineHint
+           [functionAttributeKindP|JumpTable|] -> return A.FA.JumpTable
+           [functionAttributeKindP|MinSize|] -> return A.FA.MinimizeSize
+           [functionAttributeKindP|MustProgress|] -> return A.FA.MustProgress
+           [functionAttributeKindP|Naked|] -> return A.FA.Naked
+           [functionAttributeKindP|NoBuiltin|] -> return A.FA.NoBuiltin
+           [functionAttributeKindP|NoDuplicate|] -> return A.FA.NoDuplicate
+           [functionAttributeKindP|NoFree|] -> return A.FA.NoFree
+           [functionAttributeKindP|NoImplicitFloat|] -> return A.FA.NoImplicitFloat
+           [functionAttributeKindP|NoInline|] -> return A.FA.NoInline
+           [functionAttributeKindP|NoRecurse|] -> return A.FA.NoRecurse
+           [functionAttributeKindP|NoRedZone|] -> return A.FA.NoRedZone
+           [functionAttributeKindP|NoReturn|] -> return A.FA.NoReturn
+           [functionAttributeKindP|NoSync|] -> return A.FA.NoSync
+           [functionAttributeKindP|NoUnwind|] -> return A.FA.NoUnwind
+           [functionAttributeKindP|NonLazyBind|] -> return A.FA.NonLazyBind
+           [functionAttributeKindP|OptimizeForSize|] -> return A.FA.OptimizeForSize
+           [functionAttributeKindP|OptimizeNone|] -> return A.FA.OptimizeNone
+           [functionAttributeKindP|ReadNone|] -> return A.FA.ReadNone
+           [functionAttributeKindP|ReadOnly|] -> return A.FA.ReadOnly
+           [functionAttributeKindP|ReturnsTwice|] -> return A.FA.ReturnsTwice
+           [functionAttributeKindP|SafeStack|] -> return A.FA.SafeStack
+           [functionAttributeKindP|SanitizeAddress|] -> return A.FA.SanitizeAddress
+           [functionAttributeKindP|SanitizeHWAddress|] -> return A.FA.SanitizeHWAddress
+           [functionAttributeKindP|SanitizeMemory|] -> return A.FA.SanitizeMemory
+           [functionAttributeKindP|SanitizeThread|] -> return A.FA.SanitizeThread
+           [functionAttributeKindP|Speculatable|] -> return A.FA.Speculatable
+           [functionAttributeKindP|StackAlignment|] -> return A.FA.StackAlignment `ap` (liftIO $ FFI.attributeValueAsInt a)
+           [functionAttributeKindP|StackProtectReq|] -> return A.FA.StackProtectReq
+           [functionAttributeKindP|StackProtectStrong|] -> return A.FA.StackProtectStrong
+           [functionAttributeKindP|StackProtect|] -> return A.FA.StackProtect
+           [functionAttributeKindP|StrictFP|] -> return A.FA.StrictFP
+           [functionAttributeKindP|UWTable|] -> return A.FA.UWTable
+           [functionAttributeKindP|WillReturn|] -> return A.FA.WillReturn
+           [functionAttributeKindP|WriteOnly|] -> return A.FA.WriteOnly
+           _ -> error $ "unhandled function attribute enum value: " ++ show enum
+
+allocaAttrBuilder :: (Monad m, MonadAnyCont IO m) => m (Ptr (FFI.AttrBuilder a))
+allocaAttrBuilder = do
+  p <- allocaArray FFI.getAttrBuilderSize
+  anyContToM $ \f -> do
+    ab <- FFI.constructAttrBuilder p
+    r <- f ab
+    FFI.destroyAttrBuilder ab
+    return r
+
+instance forall a b. EncodeM EncodeAST a (Ptr (FFI.AttrBuilder b) -> EncodeAST ()) =>
+         EncodeM EncodeAST [a] (FFI.AttributeSet b) where
+  encodeM as = do
+    ab <- allocaAttrBuilder
+    builds <- mapM encodeM as
+    void (forM builds ($ ab) :: EncodeAST [()])
+    Context context <- gets encodeStateContext
+    anyContToM
+      (bracket (FFI.getAttributeSet context ab) FFI.disposeAttributeSet)
+
+instance forall a b. DecodeM DecodeAST a (FFI.Attribute b) => DecodeM DecodeAST [a] (FFI.AttributeSet b) where
+  decodeM as = do
+    numAttributes <- liftIO (FFI.getNumAttributes as)
+    attrs <- allocaArray numAttributes
+    liftIO (FFI.getAttributes as attrs)
+    decodeM (numAttributes, attrs :: Ptr (FFI.Attribute b))
+
+data AttributeList = AttributeList {
+    functionAttributes :: [Either A.FA.GroupID A.FA.FunctionAttribute],
+    returnAttributes :: [A.PA.ParameterAttribute],
+    parameterAttributes :: [[A.PA.ParameterAttribute]]
+  }
+  deriving (Eq, Show)
+
+data PreSlot
+  = IndirectFunctionAttributes A.FA.GroupID
+  | DirectFunctionAttributes [A.FA.FunctionAttribute]
+  | ReturnAttributes [A.PA.ParameterAttribute]
+  | ParameterAttributes CUInt [A.PA.ParameterAttribute]
+
+instance {-# OVERLAPPING #-} EncodeM EncodeAST [Either A.FA.GroupID A.FA.FunctionAttribute] FFI.FunctionAttributeSet where
+  encodeM attrs = do
+    ab <- allocaAttrBuilder
+    forM_ attrs $ \attr ->
+      case attr of
+        Left groupId -> do
+          attrSet <- referAttributeGroup groupId
+          ab' <- anyContToM (bracket (FFI.attrBuilderFromSet attrSet) FFI.disposeAttrBuilder)
+          liftIO (FFI.mergeAttrBuilder ab ab')
+        Right attr -> do
+          addAttr <- encodeM attr
+          addAttr ab :: EncodeAST ()
+    Context context <- gets encodeStateContext
+    anyContToM
+      (bracket (FFI.getAttributeSet context ab) FFI.disposeAttributeSet)
+
+instance EncodeM EncodeAST AttributeList FFI.AttributeList where
+  encodeM (AttributeList fAttrs rAttrs pAttrs) = do
+    fAttrSet <- encodeM fAttrs
+    rAttrSet <- encodeM rAttrs :: EncodeAST FFI.ParameterAttributeSet
+    (numPAttrs, pAttrSets) <- encodeM pAttrs
+    Context context <- gets encodeStateContext
+    anyContToM
+      (bracket
+         (FFI.buildAttributeList context fAttrSet rAttrSet pAttrSets numPAttrs)
+         FFI.disposeAttributeList)
+
+instance DecodeM DecodeAST AttributeList (FFI.AttrSetDecoder a, a) where
+  decodeM (FFI.AttrSetDecoder attrsAtIndex countParams, a) = do
+    functionAttrSet <-
+      do mAttrSet <-
+           -- function attributes are grouped and decoded later. Since
+           -- we are sometimes decoding inside of scopeAnyConT, we
+           -- cannot use withAttrsAtIndex to allocate the attribute
+           -- set since it will be freed before we decode it.
+           liftIO . mask_ $ do
+             attrSet <-
+               attrsAtIndex a FFI.functionIndex :: IO FFI.FunctionAttributeSet
+             hasAttributes <- decodeM =<< FFI.attributeSetHasAttributes attrSet
+             if hasAttributes
+               then pure (Just attrSet)
+               else FFI.disposeAttributeSet attrSet >> pure Nothing
+         case mAttrSet of
+           Nothing -> pure Nothing
+           Just attrSet -> Just . Left <$> getAttributeGroupID attrSet
+    returnAttrs <-
+      do attrSet <-
+           withAttrsAtIndex FFI.returnIndex :: DecodeAST FFI.ParameterAttributeSet
+         decodeM attrSet
+    numParams <- liftIO (countParams a)
+    paramAttrs <-
+      forM [1 .. numParams] $ \i ->
+        decodeM =<<
+        (withAttrsAtIndex (FFI.AttributeIndex i) :: DecodeAST FFI.ParameterAttributeSet)
+    return
+      (AttributeList
+       { functionAttributes = maybeToList functionAttrSet
+       , returnAttributes = returnAttrs
+       , parameterAttributes = paramAttrs
+       })
+    where
+      withAttrsAtIndex :: FFI.AttributeIndex -> DecodeAST (FFI.AttributeSet b)
+      withAttrsAtIndex index =
+        anyContToM (bracket (attrsAtIndex a index) (FFI.disposeAttributeSet))
diff --git a/src/LLVM/Internal/BasicBlock.hs b/src/LLVM/Internal/BasicBlock.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/BasicBlock.hs
@@ -0,0 +1,27 @@
+module LLVM.Internal.BasicBlock where
+
+import LLVM.Prelude
+
+import Control.Monad.Trans
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.BasicBlock as FFI
+import qualified LLVM.Internal.FFI.Iterate as FFI
+
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.Coding
+import LLVM.Internal.Instruction ()
+
+import qualified LLVM.AST.Instruction as A
+
+getBasicBlockTerminator :: Ptr FFI.BasicBlock -> DecodeAST (DecodeAST (A.Named A.Terminator))
+getBasicBlockTerminator = decodeM <=< (liftIO . FFI.getBasicBlockTerminator)
+
+getNamedInstructions :: Ptr FFI.BasicBlock -> DecodeAST (DecodeAST [A.Named A.Instruction])
+getNamedInstructions b = do
+  ffiInstructions <- liftIO $ FFI.getXs (FFI.getFirstInstruction b) FFI.getNextInstruction
+  let n = length ffiInstructions
+  liftM sequence . forM (take (n-1) ffiInstructions) $ decodeM
+
+  
diff --git a/src/LLVM/Internal/CallingConvention.hs b/src/LLVM/Internal/CallingConvention.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/CallingConvention.hs
@@ -0,0 +1,107 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  TemplateHaskell,
+  QuasiQuotes
+  #-}
+module LLVM.Internal.CallingConvention where
+
+import LLVM.Prelude
+
+import LLVM.Internal.Coding
+import Foreign.C.Types (CUInt(..))
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import LLVM.Internal.FFI.LLVMCTypes (callingConventionP)
+
+import qualified LLVM.AST.CallingConvention as A.CC
+
+instance Monad m => EncodeM m A.CC.CallingConvention FFI.CallingConvention where
+  encodeM cc = return $ 
+        case cc of
+          A.CC.C -> FFI.callingConventionC
+          A.CC.Fast -> FFI.callingConventionFast
+          A.CC.Cold -> FFI.callingConventionCold
+          A.CC.GHC -> FFI.callingConventionGHC
+          A.CC.HiPE -> FFI.callingConventionHiPE
+          A.CC.WebKit_JS -> FFI.callingConventionWebKit_JS
+          A.CC.AnyReg -> FFI.callingConventionAnyReg
+          A.CC.PreserveMost -> FFI.callingConventionPreserveMost
+          A.CC.PreserveAll -> FFI.callingConventionPreserveAll
+          A.CC.Swift -> FFI.callingConventionSwift
+          A.CC.CXX_FastTLS -> FFI.callingConventionCXX_FAST_TLS
+          A.CC.X86_StdCall -> FFI.callingConventionX86_StdCall
+          A.CC.X86_FastCall -> FFI.callingConventionX86_FastCall
+          A.CC.ARM_APCS -> FFI.callingConventionARM_APCS
+          A.CC.ARM_AAPCS -> FFI.callingConventionARM_AAPCS
+          A.CC.ARM_AAPCS_VFP -> FFI.callingConventionARM_AAPCS_VFP
+          A.CC.MSP430_INTR -> FFI.callingConventionMSP430_INTR
+          A.CC.X86_ThisCall -> FFI.callingConventionX86_ThisCall
+          A.CC.PTX_Kernel -> FFI.callingConventionPTX_Kernel
+          A.CC.PTX_Device -> FFI.callingConventionPTX_Device
+          A.CC.SPIR_FUNC -> FFI.callingConventionSPIR_FUNC
+          A.CC.SPIR_KERNEL -> FFI.callingConventionSPIR_KERNEL
+          A.CC.Intel_OCL_BI -> FFI.callingConventionIntel_OCL_BI
+          A.CC.X86_64_SysV -> FFI.callingConventionX86_64_SysV
+          A.CC.Win64 -> FFI.callingConventionWin64
+          A.CC.X86_VectorCall -> FFI.callingConventionX86_VectorCall
+          A.CC.HHVM -> FFI.callingConventionHHVM
+          A.CC.HHVM_C -> FFI.callingConventionHHVM_C
+          A.CC.X86_Intr -> FFI.callingConventionX86_INTR
+          A.CC.AVR_Intr -> FFI.callingConventionAVR_INTR
+          A.CC.AVR_Signal -> FFI.callingConventionAVR_SIGNAL
+          A.CC.AVR_Builtin -> FFI.callingConventionAVR_BUILTIN
+          A.CC.AMDGPU_VS -> FFI.callingConventionAMDGPU_VS
+          A.CC.AMDGPU_HS -> FFI.callingConventionAMDGPU_HS
+          A.CC.AMDGPU_GS -> FFI.callingConventionAMDGPU_GS
+          A.CC.AMDGPU_PS -> FFI.callingConventionAMDGPU_PS
+          A.CC.AMDGPU_CS -> FFI.callingConventionAMDGPU_CS
+          A.CC.AMDGPU_Kernel -> FFI.callingConventionAMDGPU_KERNEL
+          A.CC.X86_RegCall -> FFI.callingConventionX86_RegCall
+          A.CC.MSP430_Builtin -> FFI.callingConventionMSP430_BUILTIN
+          A.CC.Numbered cc' -> FFI.CallingConvention (fromIntegral cc')
+
+instance Monad m => DecodeM m A.CC.CallingConvention FFI.CallingConvention where
+  decodeM cc = return $ case cc of
+    [callingConventionP|C|] -> A.CC.C
+    [callingConventionP|Fast|] -> A.CC.Fast
+    [callingConventionP|Cold|] -> A.CC.Cold
+    [callingConventionP|GHC|] -> A.CC.GHC
+    [callingConventionP|HiPE|] -> A.CC.HiPE
+    [callingConventionP|WebKit_JS|] -> A.CC.WebKit_JS
+    [callingConventionP|AnyReg|] -> A.CC.AnyReg
+    [callingConventionP|PreserveMost|] -> A.CC.PreserveMost
+    [callingConventionP|PreserveAll|] -> A.CC.PreserveAll
+    [callingConventionP|Swift|] -> A.CC.Swift
+    [callingConventionP|CXX_FAST_TLS|] -> A.CC.CXX_FastTLS
+    [callingConventionP|X86_StdCall|] -> A.CC.X86_StdCall
+    [callingConventionP|X86_FastCall|] -> A.CC.X86_FastCall
+    [callingConventionP|ARM_APCS|] -> A.CC.ARM_APCS
+    [callingConventionP|ARM_AAPCS|] -> A.CC.ARM_AAPCS
+    [callingConventionP|ARM_AAPCS_VFP|] -> A.CC.ARM_AAPCS_VFP
+    [callingConventionP|MSP430_INTR|] -> A.CC.MSP430_INTR
+    [callingConventionP|X86_ThisCall|] -> A.CC.X86_ThisCall
+    [callingConventionP|PTX_Kernel|] -> A.CC.PTX_Kernel
+    [callingConventionP|PTX_Device|] -> A.CC.PTX_Device
+    [callingConventionP|SPIR_FUNC|] -> A.CC.SPIR_FUNC
+    [callingConventionP|SPIR_KERNEL|] -> A.CC.SPIR_KERNEL
+    [callingConventionP|Intel_OCL_BI|] -> A.CC.Intel_OCL_BI
+    [callingConventionP|X86_64_SysV|] -> A.CC.X86_64_SysV
+    [callingConventionP|Win64|] -> A.CC.Win64
+    [callingConventionP|X86_VectorCall|] -> A.CC.X86_VectorCall
+    [callingConventionP|HHVM|] -> A.CC.HHVM
+    [callingConventionP|HHVM_C|] -> A.CC.HHVM_C
+    [callingConventionP|X86_INTR|] -> A.CC.X86_Intr
+    [callingConventionP|AVR_INTR|] -> A.CC.AVR_Intr
+    [callingConventionP|AVR_SIGNAL|] -> A.CC.AVR_Signal
+    [callingConventionP|AVR_BUILTIN|] -> A.CC.AVR_Builtin
+    [callingConventionP|AMDGPU_VS|] -> A.CC.AMDGPU_VS
+    [callingConventionP|AMDGPU_HS|] -> A.CC.AMDGPU_HS
+    [callingConventionP|AMDGPU_GS|] -> A.CC.AMDGPU_GS
+    [callingConventionP|AMDGPU_PS|] -> A.CC.AMDGPU_PS
+    [callingConventionP|AMDGPU_CS|] -> A.CC.AMDGPU_CS
+    [callingConventionP|AMDGPU_KERNEL|] -> A.CC.AMDGPU_Kernel
+    [callingConventionP|X86_RegCall|] -> A.CC.X86_RegCall
+    [callingConventionP|MSP430_BUILTIN|] -> A.CC.MSP430_Builtin
+    FFI.CallingConvention (CUInt ci)
+      | ci >= 64 -> A.CC.Numbered (fromIntegral ci)
+      | otherwise -> error ("Unknown calling convention: " <> show ci)
diff --git a/src/LLVM/Internal/Coding.hs b/src/LLVM/Internal/Coding.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Coding.hs
@@ -0,0 +1,154 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses,
+  FunctionalDependencies,
+  UndecidableInstances
+  #-}
+module LLVM.Internal.Coding where
+
+import LLVM.Prelude
+
+import Language.Haskell.TH
+import Language.Haskell.TH.Quote
+
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+
+import Foreign.C
+import Foreign.Ptr
+import Foreign.Storable (Storable)
+import qualified Foreign.Storable
+import qualified Foreign.Marshal.Alloc
+import qualified Foreign.Marshal.Array
+import GHC.Stack
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+class EncodeM e h c where
+  encodeM :: HasCallStack => h -> e c
+
+class DecodeM d h c where
+  decodeM :: HasCallStack => c -> d h
+
+genCodingInstance :: (Data c, Data h) => TypeQ -> Name -> [(c, h)] -> Q [Dec]
+genCodingInstance ht ctn chs = do
+  let n = const Nothing
+  [d| 
+    instance Monad m => EncodeM m $(ht) $(conT ctn) where
+      encodeM h = return $(
+        caseE [| h |] [ match (dataToPatQ n h) (normalB (dataToExpQ n c)) [] | (c,h) <- chs ] 
+       )
+
+    instance Monad m => DecodeM m $(ht) $(conT ctn) where
+      decodeM c = return $(
+        caseE [| c |] ([ match (dataToPatQ n c) (normalB (dataToExpQ n h)) [] | (c,h) <- chs] ++
+                       [ match wildP (normalB [e| error ("Decoding failed: Unknown " <> show c) |]) []]))
+   |]
+
+allocaArray :: (Integral i, Storable a, MonadAnyCont IO m) => i -> m (Ptr a)
+allocaArray p = anyContToM $ Foreign.Marshal.Array.allocaArray (fromIntegral p)
+
+alloca :: (Storable a, MonadAnyCont IO m) => m (Ptr a)
+alloca = anyContToM Foreign.Marshal.Alloc.alloca
+
+peek :: (Storable a, MonadIO m) => Ptr a -> m a
+peek p = liftIO $ Foreign.Storable.peek p
+
+peekByteOff :: (Storable a, MonadIO m) => Ptr a -> Int -> m a
+peekByteOff p i = liftIO $ Foreign.Storable.peekByteOff p i
+
+poke :: (Storable a, MonadIO m) => Ptr a -> a -> m ()
+poke p a = liftIO $ Foreign.Storable.poke p a
+
+pokeByteOff :: (Storable a, MonadIO m) => Ptr a -> Int -> a -> m ()
+pokeByteOff p i a = liftIO $ Foreign.Storable.pokeByteOff p i a
+
+peekArray :: (Integral i, Storable a, MonadIO m) => i -> Ptr a -> m [a]
+peekArray n p = liftIO $ Foreign.Marshal.Array.peekArray (fromIntegral n) p
+
+instance (Monad m, EncodeM m h c, Storable c, MonadAnyCont IO m) => EncodeM m [h] (CUInt, Ptr c) where
+  encodeM hs = do
+    hs <- mapM encodeM hs
+    (anyContToM $ \x -> Foreign.Marshal.Array.withArrayLen hs $ \n hs -> x (fromIntegral n, hs))
+
+instance (Monad m, DecodeM m h c, Storable c, MonadIO m) => DecodeM m [h] (CUInt, Ptr c) where
+  decodeM (n, ca) = do
+    cs <- liftIO $ Foreign.Marshal.Array.peekArray (fromIntegral n) ca
+    mapM decodeM cs
+
+instance Monad m => EncodeM m Bool FFI.LLVMBool where
+  encodeM False = return $ FFI.LLVMBool 0
+  encodeM True = return $ FFI.LLVMBool 1
+
+instance Monad m => DecodeM m Bool FFI.LLVMBool where
+  decodeM (FFI.LLVMBool 0) = return $ False
+  decodeM (FFI.LLVMBool _) = return $ True
+
+instance (Monad m, EncodeM m h (Ptr c)) => EncodeM m (Maybe h) (Ptr c) where
+  encodeM = maybe (return nullPtr) encodeM
+
+instance (Monad m, DecodeM m h (Ptr c)) => DecodeM m (Maybe h) (Ptr c) where
+  decodeM p | p == nullPtr = return Nothing
+            | otherwise = liftM Just $ decodeM p
+
+instance Monad m => EncodeM m (Maybe Bool) (FFI.NothingAsMinusOne Bool) where
+  encodeM = return . FFI.NothingAsMinusOne . maybe (-1) (fromIntegral . fromEnum)
+
+instance Monad m => EncodeM m (Maybe Word) (FFI.NothingAsMinusOne Word) where
+  encodeM = return . FFI.NothingAsMinusOne . maybe (-1) fromIntegral
+
+instance Monad m => EncodeM m (Maybe Word32) (CUInt, FFI.LLVMBool) where
+  encodeM (Just a) = liftM2 (,) (encodeM a) (encodeM True)
+  encodeM Nothing = (0,) <$> encodeM False
+
+instance Monad m => EncodeM m (Maybe Word32) (Word32, FFI.LLVMBool) where
+  encodeM (Just a) = (a,) <$> encodeM True
+  encodeM Nothing = (0,) <$> encodeM False
+
+instance Monad m => EncodeM m Word CUInt where
+  encodeM = return . fromIntegral
+
+instance Monad m => EncodeM m Word32 CUInt where
+  encodeM = return . fromIntegral
+
+instance Monad m => EncodeM m Word64 CULong where
+  encodeM = return . fromIntegral
+
+instance Monad m => DecodeM m Word CUInt where
+  decodeM = return . fromIntegral
+
+instance Monad m => DecodeM m Word32 CUInt where
+  decodeM = return . fromIntegral
+
+instance Monad m => DecodeM m Word64 CULong where
+  decodeM = return . fromIntegral
+
+instance Monad m => EncodeM m Int32 CInt where
+  encodeM = return . fromIntegral
+
+instance Monad m => DecodeM m Int32 CInt where
+  decodeM = return . fromIntegral
+
+instance Monad m => DecodeM m Int CInt where
+  decodeM = return . fromIntegral
+
+instance Monad m => EncodeM m Word64 Word64 where
+  encodeM = return
+
+instance Monad m => DecodeM m Word64 Word64 where
+  decodeM = return
+
+decodeOptional :: (DecodeM m b a, Storable a, MonadAnyCont IO m, MonadIO m) => (Ptr a -> IO FFI.LLVMBool) -> m (Maybe b)
+decodeOptional f = do
+  ptr <- alloca
+  isJust <- decodeM =<< liftIO (f ptr)
+  if isJust
+    then Just <$> (decodeM =<< peek ptr)
+    else pure Nothing
+
+decodeArray :: (DecodeM m b' b, MonadIO m) => (a -> IO CUInt) -> (a -> CUInt -> IO b) -> a -> m [b']
+decodeArray numElems getElem a = do
+  n <- liftIO (numElems a)
+  if n == 0
+    then pure []
+    else traverse (decodeM <=< liftIO . getElem a) [0 .. n - 1]
diff --git a/src/LLVM/Internal/CommandLine.hs b/src/LLVM/Internal/CommandLine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/CommandLine.hs
@@ -0,0 +1,23 @@
+module LLVM.Internal.CommandLine where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.CommandLine as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1cl.html#a992a39dae9eb8d4e54ffee5467902803>
+-- Sadly, there is occasionally some configuration one would like to control
+-- in LLVM which are accessible only as command line flags setting global state,
+-- as if the command line tools were the only use of LLVM. Very sad.
+parseCommandLineOptions :: [ShortByteString] -> Maybe ShortByteString -> IO ()
+parseCommandLineOptions args overview = runAnyContT' return $ do
+  args <- encodeM args
+  overview <- maybe (return nullPtr) encodeM overview
+  liftIO $ FFI.parseCommandLineOptions args overview
diff --git a/src/LLVM/Internal/Constant.hs b/src/LLVM/Internal/Constant.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Constant.hs
@@ -0,0 +1,322 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  QuasiQuotes,
+  MultiParamTypeClasses,
+  ScopedTypeVariables
+  #-}
+module LLVM.Internal.Constant where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+import qualified Language.Haskell.TH.Quote as TH
+import qualified LLVM.Internal.InstructionDefs as ID
+
+import Data.Bits
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+import Control.Monad.State (get, gets, modify, evalState)
+
+import qualified Data.Map as Map
+import Foreign.Ptr
+import Foreign.Storable (Storable, sizeOf)
+
+import qualified LLVM.Internal.FFI.Constant as FFI
+import qualified LLVM.Internal.FFI.GlobalValue as FFI
+import qualified LLVM.Internal.FFI.Instruction as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import LLVM.Internal.FFI.LLVMCTypes (valueSubclassIdP)
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Type as FFI
+import qualified LLVM.Internal.FFI.User as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+import qualified LLVM.Internal.FFI.BinaryOperator as FFI
+
+import qualified LLVM.AST.Constant as A (Constant)
+import qualified LLVM.AST.Constant as A.C hiding (Constant)
+import qualified LLVM.AST.Type as A
+import qualified LLVM.AST.IntegerPredicate as A (IntegerPredicate)
+import qualified LLVM.AST.FloatingPointPredicate as A (FloatingPointPredicate)
+import qualified LLVM.AST.Float as A.F
+
+import LLVM.Exception
+import LLVM.Internal.Coding
+import LLVM.Internal.Context
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.FloatingPointPredicate ()
+import LLVM.Internal.IntegerPredicate ()
+import LLVM.Internal.Type (renameType)
+import LLVM.Internal.Value
+
+allocaWords :: forall a m . (Storable a, MonadAnyCont IO m, Monad m, MonadIO m) => Word32 -> m (Ptr a)
+allocaWords nBits = do
+  allocaArray (((nBits-1) `div` (8*(fromIntegral (sizeOf (undefined :: a))))) + 1)
+
+inconsistentCases :: Show a => String -> a -> b
+inconsistentCases name attr =
+  error $ "llvm-hs internal error: cases inconstistent in " ++ name ++ " encoding for " ++ show attr
+
+instance EncodeM EncodeAST A.Constant (Ptr FFI.Constant) where
+  encodeM c = scopeAnyCont $ case c of
+    A.C.Int { A.C.integerBits = bits, A.C.integerValue = v } -> do
+      t <- encodeM (A.IntegerType bits)
+      words <- encodeM [
+        fromIntegral ((v `shiftR` (w*64)) .&. 0xffffffffffffffff) :: Word64
+        | w <- [0 .. ((fromIntegral bits-1) `div` 64)]
+       ]
+      liftIO $ FFI.constantIntOfArbitraryPrecision t words
+    A.C.Float { A.C.floatValue = v } -> do
+      Context context <- gets encodeStateContext
+      let poke1 f = do
+            let nBits = fromIntegral $ 8*(sizeOf f)
+            words <- allocaWords nBits
+            poke (castPtr words) f
+            return (nBits, words)
+          poke2 fh fl = do
+             let nBits = fromIntegral $ 8*(sizeOf fh) + 8*(sizeOf fl)
+             words <- allocaWords nBits
+             pokeByteOff (castPtr words) 0 fl
+             pokeByteOff (castPtr words) (sizeOf fl) fh
+             return (nBits, words)
+      (nBits, words) <- case v of
+        A.F.Half f -> poke1 f
+        A.F.Single f -> poke1 f
+        A.F.Double f -> poke1 f
+        A.F.X86_FP80 high low -> poke2 high low
+        A.F.Quadruple high low -> poke2 high low
+        A.F.PPC_FP128 high low -> poke2 high low
+      let fpSem = case v of
+                    A.F.Half _ -> FFI.floatSemanticsIEEEhalf
+                    A.F.Single _ -> FFI.floatSemanticsIEEEsingle
+                    A.F.Double _ -> FFI.floatSemanticsIEEEdouble
+                    A.F.Quadruple _ _ -> FFI.floatSemanticsIEEEquad
+                    A.F.X86_FP80 _ _ -> FFI.floatSemanticsx87DoubleExtended
+                    A.F.PPC_FP128 _ _ -> FFI.floatSemanticsPPCDoubleDouble
+      nBits <- encodeM nBits
+      liftIO $ FFI.constantFloatOfArbitraryPrecision context nBits words fpSem
+    A.C.GlobalReference ty n -> do
+      ref <- FFI.upCast <$> referGlobal n
+      ty' <- (liftIO . runDecodeAST . typeOf) ref
+      renamedTy <- renameType ty
+      if renamedTy /= ty'
+        then throwM
+               (EncodeException
+                  ("The serialized GlobalReference " ++ show n  ++ " has type " ++ show ty ++ " but should have type " ++ show ty'))
+        else return ref
+    A.C.BlockAddress f b -> do
+      f' <- referGlobal f
+      b' <- getBlockForAddress f b
+      liftIO $ FFI.blockAddress (FFI.upCast f') b'
+    A.C.Struct nm p ms -> do
+      p <- encodeM p
+      ms <- encodeM ms
+      case nm of
+        Nothing -> do
+          Context context <- gets encodeStateContext
+          liftIO $ FFI.constStructInContext context ms p
+        Just nm -> do
+          t <- lookupNamedType nm
+          liftIO $ FFI.constNamedStruct t ms
+    A.C.TokenNone -> do
+      Context context <- gets encodeStateContext
+      liftIO $ FFI.getConstTokenNone context
+    o -> $(do
+      let -- This is a mapping from constructor names to the constructor of the constant
+          -- and the constructor and the definition of the instruction.
+          constExprInfo :: Map.Map String (Maybe TH.Con, Maybe (TH.Con, ID.InstructionDef))
+          constExprInfo =  ID.outerJoin ID.astConstantRecs (ID.innerJoin ID.astInstructionRecs ID.instructionDefs)
+      TH.caseE [| o |] $
+        map (\p -> TH.match p (TH.normalB [|inconsistentCases "Constant" o|]) [])
+            [[p|A.C.Int{}|],
+             [p|A.C.Float{}|],
+             [p|A.C.Struct{}|],
+             [p|A.C.BlockAddress{}|],
+             [p|A.C.GlobalReference{}|],
+             [p|A.C.TokenNone{}|]] ++
+        (do (name, (Just (TH.RecC n fields), instrInfo)) <- Map.toList constExprInfo
+            let fieldNames = [ TH.mkName . TH.nameBase $ fn | (fn, _, _) <- fields ]
+                coreCall n = TH.dyn $ "FFI.constant" ++ n
+                -- Addition validations that are run during encoding. A common usage of
+                -- this is to check if certain types are allowed. The record fields are in scope
+                -- when the validations are run.
+                validations = case name of
+                  "Null" ->
+                    [ TH.noBindS
+                        [| case $(TH.dyn "constantType") of
+                             A.PointerType {} -> pure ()
+                             _ ->
+                               throwM
+                                 (EncodeException
+                                    ("Null pointer constant must have pointer type but has type " <>
+                                     show $(TH.dyn "constantType") <> "."))
+                        |]
+                    ]
+                  "AggregateZero" ->
+                    [ TH.noBindS $
+                        [| case $(TH.dyn "constantType") of
+                             A.ArrayType {} -> pure ()
+                             A.StructureType {} -> pure ()
+                             A.VectorType {} -> pure ()
+                             A.NamedTypeReference {} -> pure ()
+                             _ ->
+                               throwM
+                                 (EncodeException
+                                    ("Aggregate zero constant must have struct, array or vector type but has type " <>
+                                     show $(TH.dyn "constantType") <> "."))
+                        |]
+                    ]
+                  _ -> []
+                buildBody c =
+                  validations ++
+                  [ TH.bindS (TH.varP fn) [| encodeM $(TH.varE fn) |] | fn <- fieldNames ] ++
+                  [ TH.noBindS [| liftIO $(foldl TH.appE c (map TH.varE fieldNames)) |] ]
+                hasFlags = ''Bool `elem` [ h | (_, _, TH.ConT h) <- fields ]
+            core <- case instrInfo of
+              Just (_, iDef) -> do
+                let opcode = TH.dataToExpQ (const Nothing) (ID.cppOpcode iDef)
+                case ID.instructionKind iDef of
+                  ID.Binary
+                    | hasFlags -> return $ coreCall name
+                    | otherwise -> return [| $(coreCall "BinaryOperator") $(opcode) |]
+                  ID.Cast -> return [| $(coreCall "Cast") $(opcode) |]
+                  _ -> return $ coreCall name
+              Nothing ->
+                case name of
+                  "Array" -> pure (TH.varE 'FFI.constantArray)
+                  "AggregateZero" -> pure (TH.varE 'FFI.constantNull)
+                  "Null" -> pure (TH.varE 'FFI.constantNull)
+                  "Undef" -> pure (TH.varE 'FFI.constantUndef)
+                  "Vector" -> pure (TH.varE 'FFI.constantVector)
+                  _ -> [] -- We have already handled these values
+            return $ TH.match
+              (TH.recP n [(fn,) <$> (TH.varP . TH.mkName . TH.nameBase $ fn) | (fn, _, _) <- fields])
+              (TH.normalB (TH.doE (buildBody core)))
+              [])
+     )
+
+instance DecodeM DecodeAST A.Constant (Ptr FFI.Constant) where
+  decodeM c = scopeAnyCont $ do
+    let v = FFI.upCast c :: Ptr FFI.Value
+        u = FFI.upCast c :: Ptr FFI.User
+    ft <- liftIO (FFI.typeOf v)
+    t <- decodeM ft
+    valueSubclassId <- liftIO $ FFI.getValueSubclassId v
+    nOps <- liftIO $ FFI.getNumOperands u
+    let globalRef = return A.C.GlobalReference
+                    `ap` (return t)
+                    `ap` (getGlobalName =<< liftIO (FFI.isAGlobalValue v))
+        op = decodeM <=< liftIO . FFI.getConstantOperand c
+        getConstantOperands = mapM op [0..nOps-1]
+        getConstantData = do
+          let nElements =
+                case t of
+                  A.VectorType n _ -> n
+                  A.ArrayType n _ | n <= (fromIntegral (maxBound :: Word32)) -> fromIntegral n
+                  _ -> error "getConstantData can only be applied to vectors and arrays"
+          forM [0..nElements-1] $ do
+             decodeM <=< liftIO . FFI.getConstantDataSequentialElementAsConstant c . fromIntegral
+
+    case valueSubclassId of
+      [valueSubclassIdP|Function|] -> globalRef
+      [valueSubclassIdP|GlobalAlias|] -> globalRef
+      [valueSubclassIdP|GlobalVariable|] -> globalRef
+      [valueSubclassIdP|ConstantInt|] -> do
+        np <- alloca
+        wsp <- liftIO $ FFI.getConstantIntWords c np
+        n <- peek np
+        words <- decodeM (n, wsp)
+        return $ A.C.Int (A.typeBits t) (foldr (\b a -> (a `shiftL` 64) .|. fromIntegral b) 0 (words :: [Word64]))
+      [valueSubclassIdP|ConstantFP|] -> do
+        let A.FloatingPointType fpt = t
+        let nBits = case fpt of
+                A.HalfFP      -> 16
+                A.FloatFP     -> 32
+                A.DoubleFP    -> 64
+                A.FP128FP     -> 128
+                A.X86_FP80FP  -> 80
+                A.PPC_FP128FP -> 128
+        ws <- allocaWords nBits
+        liftIO $ FFI.getConstantFloatWords c ws
+        A.C.Float <$> (
+          case fpt of
+            A.HalfFP      -> A.F.Half <$> peek (castPtr ws)
+            A.FloatFP     -> A.F.Single <$> peek (castPtr ws)
+            A.DoubleFP    -> A.F.Double <$> peek (castPtr ws)
+            A.FP128FP     -> A.F.Quadruple <$> peekByteOff (castPtr ws) 8 <*> peekByteOff (castPtr ws) 0
+            A.X86_FP80FP  -> A.F.X86_FP80 <$> peekByteOff (castPtr ws) 8 <*> peekByteOff (castPtr ws) 0
+            A.PPC_FP128FP -> A.F.PPC_FP128 <$> peekByteOff (castPtr ws) 8 <*> peekByteOff (castPtr ws) 0
+          )
+      [valueSubclassIdP|ConstantPointerNull|] -> return $ A.C.Null t
+      [valueSubclassIdP|ConstantAggregateZero|] -> return $ A.C.AggregateZero t
+      [valueSubclassIdP|UndefValue|] -> return $ A.C.Undef t
+      [valueSubclassIdP|BlockAddress|] ->
+            return A.C.BlockAddress
+               `ap` (getGlobalName =<< do liftIO $ FFI.isAGlobalValue =<< FFI.getBlockAddressFunction c)
+               `ap` (getLocalName =<< do liftIO $ FFI.getBlockAddressBlock c)
+      [valueSubclassIdP|ConstantStruct|] -> do
+            return A.C.Struct
+               `ap` (return $ case t of A.NamedTypeReference n -> Just n; _ -> Nothing)
+               `ap` (decodeM =<< liftIO (FFI.isPackedStruct ft))
+               `ap` getConstantOperands
+      [valueSubclassIdP|ConstantDataArray|] ->
+            return A.C.Array `ap` (return $ A.elementType t) `ap` getConstantData
+      [valueSubclassIdP|ConstantArray|] ->
+            return A.C.Array `ap` (return $ A.elementType t) `ap` getConstantOperands
+      [valueSubclassIdP|ConstantDataVector|] ->
+            return A.C.Vector `ap` getConstantData
+      [valueSubclassIdP|ConstantVector|] ->
+            A.C.Vector <$> getConstantOperands
+      [valueSubclassIdP|ConstantExpr|] -> do
+            cppOpcode <- liftIO $ FFI.getConstantCPPOpcode c
+            $(
+              TH.caseE [| cppOpcode |] $
+                (do (_, ((TH.RecC n fs, _), iDef)) <- Map.toList $
+                          ID.innerJoin (ID.innerJoin ID.astConstantRecs ID.astInstructionRecs) ID.instructionDefs
+                    let apWrapper o (fn, _, ct) = do
+                          a <- case ct of
+                                 TH.ConT h
+                                   | h == ''A.Constant -> do
+                                                   operandNumber <- get
+                                                   modify (+1)
+                                                   return [| op $(TH.litE . TH.integerL $ operandNumber) |]
+                                   | h == ''A.Type -> return [| pure t |]
+                                   | h == ''A.IntegerPredicate ->
+                                     return [| liftIO $ decodeM =<< FFI.getConstantICmpPredicate c |]
+                                   | h == ''A.FloatingPointPredicate ->
+                                     return [| liftIO $ decodeM =<< FFI.getConstantFCmpPredicate c |]
+                                   | h == ''Bool -> case TH.nameBase fn of
+                                                      "inBounds" -> return [| liftIO $ decodeM =<< FFI.getInBounds v |]
+                                                      "exact" -> return [| liftIO $ decodeM =<< FFI.isExact v |]
+                                                      "nsw" -> return [| liftIO $ decodeM =<< FFI.hasNoSignedWrap v |]
+                                                      "nuw" -> return [| liftIO $ decodeM =<< FFI.hasNoUnsignedWrap v |]
+                                                      x -> error $ "constant bool field " ++ show x ++ " not handled yet"
+                                 TH.AppT TH.ListT (TH.ConT h)
+                                   | h == ''Word32 ->
+                                      return [|
+                                            do
+                                              np <- alloca
+                                              isp <- liftIO $ FFI.getConstantIndices c np
+                                              n <- peek np
+                                              decodeM (n, isp)
+                                            |]
+                                   | h == ''A.Constant &&
+                                     TH.nameBase fn == "indices" -> do
+                                       operandNumber <- get
+                                       return [| mapM op [$(TH.litE . TH.integerL $ operandNumber)..nOps-1] |]
+
+                                 _ -> error $ "unhandled constant expr field type: " ++ show fn ++ " - " ++ show ct
+                          return [| $(o) `ap` $(a) |]
+                    return $ TH.match
+                              (TH.dataToPatQ (const Nothing) (ID.cppOpcode iDef))
+                              (TH.normalB (evalState (foldM apWrapper [| return $(TH.conE n) |] fs) 0))
+                              [])
+                ++ [TH.match TH.wildP (TH.normalB [|error ("Unknown constant opcode: " <> show cppOpcode)|]) []]
+             )
+      [valueSubclassIdP|ConstantTokenNone|] -> return A.C.TokenNone
+      _ -> error $ "unhandled constant valueSubclassId: " ++ show valueSubclassId
+
+
+
+
diff --git a/src/LLVM/Internal/Context.hs b/src/LLVM/Internal/Context.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Context.hs
@@ -0,0 +1,28 @@
+module LLVM.Internal.Context where
+
+import LLVM.Prelude
+
+import Control.Exception
+import Control.Concurrent
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.Context as FFI
+
+-- | a Context object holds the state the of LLVM system needs for one thread of
+-- | LLVM compilation. Once upon a time, in early versions of LLVM, this state was global.
+-- | Then it got packed up in this object to allow multiple threads to compile at once.
+data Context = Context (Ptr FFI.Context)
+
+-- | Create a Context, run an action (to which it is provided), then destroy the Context.
+withContext :: (Context -> IO a) -> IO a
+withContext = runBound . bracket FFI.contextCreate FFI.contextDispose . (. Context)
+  where runBound = if rtsSupportsBoundThreads then runInBoundThread else id
+
+-- | Create a Context.
+createContext :: IO Context
+createContext = Context <$> FFI.contextCreate
+
+-- | Destroy a context created by 'createContext'.
+disposeContext :: Context -> IO ()
+disposeContext (Context ptr) = FFI.contextDispose ptr
diff --git a/src/LLVM/Internal/DataLayout.hs b/src/LLVM/Internal/DataLayout.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/DataLayout.hs
@@ -0,0 +1,23 @@
+module LLVM.Internal.DataLayout where
+
+import LLVM.Prelude
+
+import Control.Exception
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.DataLayout as FFI
+
+import LLVM.AST.DataLayout
+import LLVM.DataLayout
+
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+withFFIDataLayout :: DataLayout -> (Ptr FFI.DataLayout -> IO a) -> IO a
+withFFIDataLayout dl f = runAnyContT' return $ do
+  dls <- encodeM (dataLayoutToString dl)
+  liftIO $ bracket (FFI.createDataLayout dls) FFI.disposeDataLayout f
+
diff --git a/src/LLVM/Internal/DecodeAST.hs b/src/LLVM/Internal/DecodeAST.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/DecodeAST.hs
@@ -0,0 +1,188 @@
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE UndecidableInstances       #-}
+
+module LLVM.Internal.DecodeAST where
+
+import LLVM.Prelude
+
+import Control.Monad.Catch
+import Control.Monad.State
+import Control.Monad.AnyCont
+
+import Foreign.Ptr
+import Foreign.C
+
+import Data.Array (Array)
+import Data.Map (Map)
+import Data.Sequence (Seq)
+import qualified Data.Array as Array
+import qualified Data.Map as Map
+import qualified Data.Sequence as Seq
+#if __GLASGOW_HASKELL__ < 808
+import Control.Monad.Fail (MonadFail)
+#endif
+
+import qualified LLVM.Internal.FFI.Attribute as FFI
+import qualified LLVM.Internal.FFI.GlobalValue as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+import qualified LLVM.Internal.FFI.Type as FFI
+
+import qualified LLVM.AST.Name as A
+import qualified LLVM.AST.Operand as A (MetadataNodeID(..))
+import qualified LLVM.AST.Attribute as A.A
+import qualified LLVM.AST.COMDAT as A.COMDAT
+
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+type NameMap a = Map (Ptr a) Word
+
+data DecodeState = DecodeState {
+    globalVarNum :: NameMap FFI.GlobalValue,
+    localVarNum :: NameMap FFI.Value,
+    localNameCounter :: Maybe Word,
+    namedTypeNum :: NameMap FFI.Type,
+    typesToDefine :: Seq (Ptr FFI.Type),
+    metadataNodesToDefine :: Seq (A.MetadataNodeID, Ptr FFI.MDNode),
+    metadataNodes :: Map (Ptr FFI.MDNode) A.MetadataNodeID,
+    metadataKinds :: Array Word ShortByteString,
+    parameterAttributeLists :: Map FFI.ParameterAttributeSet [A.A.ParameterAttribute],
+    functionAttributeListIDs :: [(FFI.FunctionAttributeSet, A.A.GroupID)],
+    comdats :: Map (Ptr FFI.COMDAT) (ShortByteString, A.COMDAT.SelectionKind)
+  }
+
+initialDecode :: DecodeState
+initialDecode = DecodeState {
+    globalVarNum = Map.empty,
+    localVarNum = Map.empty,
+    localNameCounter = Nothing,
+    namedTypeNum = Map.empty,
+    typesToDefine = Seq.empty,
+    metadataNodesToDefine = Seq.empty,
+    metadataNodes = Map.empty,
+    metadataKinds = Array.listArray (1,0) [],
+    parameterAttributeLists = Map.empty,
+    functionAttributeListIDs = [],
+    comdats = Map.empty
+  }
+newtype DecodeAST a = DecodeAST { unDecodeAST :: AnyContT (StateT DecodeState IO) a }
+  deriving (
+    Applicative,
+    Functor,
+    Monad,
+    MonadIO,
+    MonadFail,
+    MonadState DecodeState,
+    MonadThrow,
+    MonadAnyCont IO,
+    ScopeAnyCont
+  )
+
+runDecodeAST :: DecodeAST a -> IO a
+runDecodeAST d = flip evalStateT initialDecode . runAnyContT' return . unDecodeAST $ d
+
+localScope :: DecodeAST a -> DecodeAST a
+localScope (DecodeAST x) = DecodeAST (tweak x)
+  where tweak x = do
+          modify (\s@DecodeState { localNameCounter = Nothing } -> s { localNameCounter = Just 0 })
+          r <- x
+          modify (\s@DecodeState { localNameCounter = Just _ } -> s { localNameCounter = Nothing })
+          return r
+
+getName :: (Ptr a -> IO CString)
+           -> Ptr a
+           -> (DecodeState -> NameMap a)
+           -> DecodeAST Word
+           -> DecodeAST A.Name
+getName getCString v getNameMap generate = do
+  name <- liftIO $ do
+            n <- getCString v
+            if n == nullPtr then return "" else decodeM n
+  if name /= ""
+     then
+       return $ A.Name name
+     else
+       A.UnName <$> do
+         nm <- gets getNameMap
+         maybe generate return $ Map.lookup v nm
+
+getValueName :: FFI.DescendentOf FFI.Value v => Ptr v -> (DecodeState -> NameMap v) -> DecodeAST Word -> DecodeAST A.Name
+getValueName = getName (FFI.getValueName . FFI.upCast)
+
+getLocalName :: FFI.DescendentOf FFI.Value v => Ptr v -> DecodeAST A.Name
+getLocalName v' = do
+  let v = FFI.upCast v'
+  getValueName v localVarNum $ do
+                    nm <- gets localVarNum
+                    Just n <- gets localNameCounter
+                    modify $ \s -> s { localNameCounter = Just (1 + n), localVarNum = Map.insert v n nm }
+                    return n
+
+getGlobalName :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST A.Name
+getGlobalName v' = do
+  let v = FFI.upCast v'
+  getValueName v globalVarNum $ do
+                     nm <- gets globalVarNum
+                     let n = fromIntegral $ Map.size nm
+                     modify $ \s -> s { globalVarNum = Map.insert v n nm }
+                     return n
+
+
+getTypeName :: Ptr FFI.Type -> DecodeAST A.Name
+getTypeName t = do
+  getName FFI.getStructName t namedTypeNum $ do
+                  nm <- gets namedTypeNum
+                  let n = fromIntegral $ Map.size nm
+                  modify $ \s -> s { namedTypeNum = Map.insert t n nm }
+                  return n
+
+saveNamedType :: Ptr FFI.Type -> DecodeAST ()
+saveNamedType t = do
+  modify $ \s -> s { typesToDefine = t Seq.<| typesToDefine s }
+
+getMetadataNodeID :: Ptr FFI.MDNode -> DecodeAST A.MetadataNodeID
+getMetadataNodeID p = do
+  mdns <- gets metadataNodes
+  case Map.lookup p mdns of
+    Just r -> return r
+    Nothing -> do
+      let r = A.MetadataNodeID (fromIntegral (Map.size mdns))
+      modify $ \s -> s {
+        metadataNodesToDefine = (r, p) Seq.<| metadataNodesToDefine s,
+        metadataNodes = Map.insert p r (metadataNodes s)
+      }
+      return r
+
+takeTypeToDefine :: DecodeAST (Maybe (Ptr FFI.Type))
+takeTypeToDefine = state $ \s -> case Seq.viewr (typesToDefine s) of
+  remaining Seq.:> t -> (Just t, s { typesToDefine = remaining })
+  _ -> (Nothing, s)
+
+takeMetadataNodeToDefine :: DecodeAST (Maybe (A.MetadataNodeID, Ptr FFI.MDNode))
+takeMetadataNodeToDefine = state $ \s -> case Seq.viewr (metadataNodesToDefine s) of
+  remaining Seq.:> md -> (Just md, s { metadataNodesToDefine = remaining })
+  _ -> (Nothing, s)
+
+instance DecodeM DecodeAST A.Name (Ptr FFI.BasicBlock) where
+  decodeM = getLocalName
+
+getAttributeGroupID :: FFI.FunctionAttributeSet -> DecodeAST A.A.GroupID
+getAttributeGroupID p = do
+  ids <- gets functionAttributeListIDs
+  -- What we are interested in is the AttributeSetNode inside the
+  -- AttributeSet but LLVM does not expose this. We thus have to
+  -- resort to doing a linear scan and using the operator== which is
+  -- implemented as a comparison on those AttributeSetNodes.
+  id <- liftIO (findM (\(as, _) -> decodeM =<< FFI.attributeSetsEqual as p) ids)
+  case id of
+    Nothing -> do
+      let r = A.A.GroupID (fromIntegral (length ids))
+      modify $ \s -> s { functionAttributeListIDs = (p,r) : functionAttributeListIDs s }
+      return r
+    Just (_, id') -> do
+      liftIO (FFI.disposeAttributeSet p)
+      return id'
diff --git a/src/LLVM/Internal/Diagnostic.hs b/src/LLVM/Internal/Diagnostic.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Diagnostic.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses
+  #-}  
+module LLVM.Internal.Diagnostic where
+
+import LLVM.Prelude
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.SMDiagnostic as FFI
+
+import Control.Exception
+
+import Foreign.Ptr
+
+import LLVM.Diagnostic
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+genCodingInstance [t| DiagnosticKind |] ''FFI.DiagnosticKind [
+    (FFI.diagnosticKindError, ErrorKind),
+    (FFI.diagnosticKindWarning, WarningKind),
+    (FFI.diagnosticKindNote, NoteKind)
+  ]
+
+withSMDiagnostic :: (Ptr FFI.SMDiagnostic -> IO a) -> IO a
+withSMDiagnostic = bracket FFI.createSMDiagnostic FFI.disposeSMDiagnostic
+
+getDiagnostic :: Ptr FFI.SMDiagnostic -> IO Diagnostic
+getDiagnostic p = do
+  l <- decodeM =<< FFI.getSMDiagnosticLineNo p
+  c <- decodeM =<< FFI.getSMDiagnosticColumnNo p
+  k <- decodeM =<< FFI.getSMDiagnosticKind p
+  f <- decodeM $ FFI.getSMDiagnosticFilename p
+  m <- decodeM $ FFI.getSMDiagnosticMessage p
+  lc <- decodeM $ FFI.getSMDiagnosticLineContents p
+  return $ Diagnostic { 
+    lineNumber = l, columnNumber = c, diagnosticKind = k, filename = f, message = m, lineContents = lc
+   }
+
diff --git a/src/LLVM/Internal/EncodeAST.hs b/src/LLVM/Internal/EncodeAST.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/EncodeAST.hs
@@ -0,0 +1,176 @@
+{-# LANGUAGE
+  GeneralizedNewtypeDeriving,
+  MultiParamTypeClasses,
+  UndecidableInstances,
+  OverloadedStrings
+  #-}
+module LLVM.Internal.EncodeAST where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.State
+
+import Foreign.Ptr
+import Foreign.C
+
+import qualified LLVM.Internal.FFI.ShortByteString as ShortByteString
+import qualified Data.ByteString.Short as ShortByteString
+
+import Data.Map (Map)
+import qualified Data.Map as Map
+
+import qualified LLVM.Internal.FFI.Attribute as FFI
+import qualified LLVM.Internal.FFI.Builder as FFI
+import qualified LLVM.Internal.FFI.GlobalValue as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+
+import qualified LLVM.AST as A
+import qualified LLVM.AST.Attribute as A.A
+import LLVM.Exception
+
+import LLVM.Internal.Context
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+data LocalValue
+  = ForwardValue (Ptr FFI.Value)
+  | DefinedValue (Ptr FFI.Value)
+
+data EncodeState = EncodeState {
+      encodeStateBuilder :: Ptr FFI.Builder,
+      encodeStateContext :: Context,
+      encodeStateLocals :: Map A.Name LocalValue,
+      encodeStateGlobals :: Map A.Name (Ptr FFI.GlobalValue),
+      encodeStateAllBlocks :: Map (A.Name, A.Name) (Ptr FFI.BasicBlock),
+      encodeStateBlocks :: Map A.Name (Ptr FFI.BasicBlock),
+      encodeStateMDNodes :: Map A.MetadataNodeID (Ptr FFI.MDNode),
+      encodeStateNamedTypes :: Map A.Name (Ptr FFI.Type),
+      encodeStateRenamedTypes :: Map A.Name ShortByteString,
+      encodeStateAttributeGroups :: Map A.A.GroupID FFI.FunctionAttributeSet,
+      encodeStateCOMDATs :: Map ShortByteString (Ptr FFI.COMDAT)
+    }
+
+newtype EncodeAST a = EncodeAST { unEncodeAST :: AnyContT (StateT EncodeState IO) a }
+    deriving (
+       Functor,
+       Applicative,
+       Monad,
+       MonadIO,
+       MonadState EncodeState,
+       MonadThrow,
+       MonadAnyCont IO,
+       ScopeAnyCont
+     )
+
+lookupNamedType :: A.Name -> EncodeAST (Ptr FFI.Type)
+lookupNamedType n = do
+  t <- gets $ Map.lookup n . encodeStateNamedTypes
+  maybe (throwM . EncodeException $ "reference to undefined type: " ++ show n) return t
+
+defineType :: A.Name -> Maybe ShortByteString -> Ptr FFI.Type -> EncodeAST ()
+defineType n n' t = do
+  modify $ \s -> s { encodeStateNamedTypes = Map.insert n t (encodeStateNamedTypes s) }
+  for_ n' $ \renamedName ->
+    modify $ \s -> s { encodeStateRenamedTypes = Map.insert n renamedName (encodeStateRenamedTypes s) }
+
+runEncodeAST :: Context -> EncodeAST a -> IO a
+runEncodeAST context@(Context ctx) (EncodeAST a) =
+    bracket (FFI.createBuilderInContext ctx) FFI.disposeBuilder $ \builder -> do
+      let initEncodeState = EncodeState {
+              encodeStateBuilder = builder,
+              encodeStateContext = context,
+              encodeStateLocals = Map.empty,
+              encodeStateGlobals = Map.empty,
+              encodeStateAllBlocks = Map.empty,
+              encodeStateBlocks = Map.empty,
+              encodeStateMDNodes = Map.empty,
+              encodeStateNamedTypes = Map.empty,
+              encodeStateRenamedTypes = Map.empty,
+              encodeStateAttributeGroups = Map.empty,
+              encodeStateCOMDATs = Map.empty
+            }
+      flip evalStateT initEncodeState . runAnyContT' return $ a
+
+withName :: A.Name -> (CString -> IO a) -> IO a
+withName (A.Name n) = ShortByteString.useAsCString n
+withName (A.UnName _) = withCString ""
+
+instance MonadAnyCont IO m => EncodeM m A.Name CString where
+  encodeM (A.Name n) = encodeM n
+  encodeM _ = encodeM ShortByteString.empty
+
+phase :: EncodeAST a -> EncodeAST (EncodeAST a)
+phase p = do
+  let s0 `withLocalsFrom` s1 = s0 {
+         encodeStateLocals = encodeStateLocals s1,
+         encodeStateBlocks = encodeStateBlocks s1
+        }
+  s <- get
+  return $ do
+    s' <- get
+    put $ s' `withLocalsFrom` s
+    r <- p
+    modify (`withLocalsFrom` s')
+    return r
+
+defineLocal :: FFI.DescendentOf FFI.Value v => A.Name -> Ptr v -> EncodeAST ()
+defineLocal n v' = do
+  let v = FFI.upCast v'
+  case n of
+    A.Name s
+      | ShortByteString.null s -> pure ()
+    _ -> do
+      def <- gets $ Map.lookup n . encodeStateLocals
+      case def of
+        Just (ForwardValue dummy) -> liftIO $ FFI.replaceAllUsesWith dummy v
+        Just _ -> throwM (EncodeException ("Duplicate definition of local variable: " <> show n <> "."))
+        _ -> return ()
+      modify $ \b -> b { encodeStateLocals = Map.insert n (DefinedValue v) (encodeStateLocals b) }
+
+defineGlobal :: FFI.DescendentOf FFI.GlobalValue v => A.Name -> Ptr v -> EncodeAST ()
+defineGlobal n v = modify $ \b -> b { encodeStateGlobals =  Map.insert n (FFI.upCast v) (encodeStateGlobals b) }
+
+defineMDNode :: A.MetadataNodeID -> Ptr FFI.MDNode -> EncodeAST ()
+defineMDNode n v = modify $ \b -> b { encodeStateMDNodes = Map.insert n (FFI.upCast v) (encodeStateMDNodes b) }
+
+defineAttributeGroup :: A.A.GroupID -> FFI.FunctionAttributeSet -> EncodeAST ()
+defineAttributeGroup gid attrs = modify $ \b -> b { encodeStateAttributeGroups = Map.insert gid attrs (encodeStateAttributeGroups b) }
+
+defineCOMDAT :: ShortByteString -> Ptr FFI.COMDAT -> EncodeAST ()
+defineCOMDAT name cd = modify $ \b -> b { encodeStateCOMDATs = Map.insert name cd (encodeStateCOMDATs b) }
+
+refer :: (Show n, Ord n) => (EncodeState -> Map n v) -> n -> EncodeAST v -> EncodeAST v
+refer r n f = do
+  mop <- gets $ Map.lookup n . r
+  maybe f return mop
+
+undefinedReference :: Show n => String -> n -> EncodeAST a
+undefinedReference m n = throwM . EncodeException $ "reference to undefined " ++ m ++ ": " ++ show n
+
+referOrThrow :: (Show n, Ord n) => (EncodeState -> Map n v) -> String -> n -> EncodeAST v
+referOrThrow r m n = refer r n $ undefinedReference m n
+
+referGlobal :: A.Name -> EncodeAST (Ptr FFI.GlobalValue)
+referGlobal = referOrThrow encodeStateGlobals "global"
+referMDNode :: A.MetadataNodeID -> EncodeAST (Ptr FFI.MDNode)
+referMDNode = referOrThrow encodeStateMDNodes "metadata node"
+referAttributeGroup :: A.A.GroupID -> EncodeAST FFI.FunctionAttributeSet
+referAttributeGroup = referOrThrow encodeStateAttributeGroups "attribute group"
+referCOMDAT :: ShortByteString -> EncodeAST (Ptr FFI.COMDAT)
+referCOMDAT = referOrThrow encodeStateCOMDATs "COMDAT"
+
+defineBasicBlock :: A.Name -> A.Name -> Ptr FFI.BasicBlock -> EncodeAST ()
+defineBasicBlock fn n b = modify $ \s -> s {
+  encodeStateBlocks = Map.insert n b (encodeStateBlocks s),
+  encodeStateAllBlocks = Map.insert (fn, n) b (encodeStateAllBlocks s)
+}
+
+instance EncodeM EncodeAST A.Name (Ptr FFI.BasicBlock) where
+  encodeM = referOrThrow encodeStateBlocks "block"
+
+getBlockForAddress :: A.Name -> A.Name -> EncodeAST (Ptr FFI.BasicBlock)
+getBlockForAddress fn n = referOrThrow encodeStateAllBlocks "blockaddress" (fn, n)
+
diff --git a/src/LLVM/Internal/ExecutionEngine.hs b/src/LLVM/Internal/ExecutionEngine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/ExecutionEngine.hs
@@ -0,0 +1,136 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  FunctionalDependencies,
+  OverloadedStrings,
+  RankNTypes
+  #-}
+module LLVM.Internal.ExecutionEngine where
+
+import LLVM.Prelude
+
+import Control.Exception
+import Control.Monad.IO.Class
+import Control.Monad.AnyCont
+
+import Data.IORef
+import Foreign.Ptr
+import Foreign.C (CUInt, CString)
+import Foreign.Marshal.Alloc (allocaBytes)
+
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.ExecutionEngine as FFI
+import qualified LLVM.Internal.FFI.Module as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Module
+import LLVM.Internal.Context
+import LLVM.Internal.Coding
+import qualified LLVM.CodeModel as CodeModel
+import LLVM.Internal.Target
+import qualified LLVM.AST as A
+import GHC.Stack
+
+removeModule :: Ptr FFI.ExecutionEngine -> Ptr FFI.Module -> IO ()
+removeModule e m = runAnyContT' return $ do
+  d0 <- alloca
+  d1 <- alloca
+  r <- liftIO $ FFI.removeModule e m d0 d1
+  when (r /= 0) $ fail "FFI.removeModule failure"
+
+-- | a 'ExecutableModule' e represents a 'Module' which is currently "in" an
+-- 'ExecutionEngine', and so the functions of which may be executed.
+data ExecutableModule e = ExecutableModule e (Ptr FFI.Module)
+
+-- | <http://llvm.org/doxygen/classllvm_1_1ExecutionEngine.html>
+class ExecutionEngine e f | e -> f where
+  withModuleInEngine :: e -> Module -> (ExecutableModule e -> IO a) -> IO a
+  getFunction :: HasCallStack => ExecutableModule e -> A.Name -> IO (Maybe f)
+
+instance ExecutionEngine (Ptr FFI.ExecutionEngine) (FunPtr ()) where
+  withModuleInEngine e m f = do
+    m' <- readModule m
+    bracket_ (FFI.addModule e m') (removeModule e m') (f (ExecutableModule e m'))
+  getFunction (ExecutableModule e m) (A.Name name) = runAnyContT' return $ do
+    name <- encodeM name
+    f <- liftIO $ FFI.getNamedFunction m name
+    if f == nullPtr 
+      then 
+        return Nothing
+      else
+        do
+          p <- liftIO $ FFI.getPointerToGlobal e (FFI.upCast f)
+          return $ if p == nullPtr then Nothing else Just (castPtrToFunPtr p)
+  getFunction _ _ = error "Only named functions can be looked up"
+
+withExecutionEngine :: 
+  Context ->
+  Maybe (Ptr FFI.Module) -> 
+  (Ptr (Ptr FFI.ExecutionEngine) -> Ptr FFI.Module -> Ptr (FFI.OwnerTransfered CString) -> IO CUInt) ->
+  (Ptr FFI.ExecutionEngine -> IO a) ->
+  IO a
+withExecutionEngine c m createEngine f = runAnyContT' return $ do
+  liftIO initializeNativeTarget
+  outExecutionEngine <- alloca
+  outErrorCStringPtr <- alloca
+  dummyModule <- maybe (anyContToM $
+                          withModuleFromAST c (A.Module "" "" Nothing Nothing []))
+                 (liftIO . newModule) m
+  dummyModule' <- readModule dummyModule
+  r <- liftIO $ createEngine outExecutionEngine dummyModule' outErrorCStringPtr
+  when (r /= 0) $ fail =<< decodeM outErrorCStringPtr
+  executionEngine <- anyContToM $ bracket (peek outExecutionEngine) FFI.disposeExecutionEngine
+  liftIO $ removeModule executionEngine dummyModule'
+  liftIO $ f executionEngine
+
+data MCJITState
+  = Deferred (forall a . Module -> (Ptr FFI.ExecutionEngine -> IO a) -> IO a)
+  | Constructed (Ptr FFI.ExecutionEngine)
+
+-- | <http://llvm.org/doxygen/classllvm_1_1MCJIT.html>
+-- <http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html>
+-- N.B. - the LLVM MCJIT does not current support adding multiple
+-- modules to any one instance of the MCJIT.
+newtype MCJIT = MCJIT (IORef MCJITState)
+
+-- | bracket the creation and destruction of an 'MCJIT'
+withMCJIT :: 
+  Context
+  -> Maybe Word -- ^ optimization level
+  -> Maybe CodeModel.Model
+  -> Maybe Bool -- ^ True to disable frame pointer elimination
+  -> Maybe Bool -- ^ True to enable fast instruction selection
+--  -> Maybe MemoryManager -- llvm-hs doesn't support this yet
+  -> (MCJIT -> IO a)
+  -> IO a
+withMCJIT c opt cm fpe fisel f = do
+  FFI.linkInMCJIT
+  let createMCJITCompilerForModule e m s = do
+        size <- FFI.getMCJITCompilerOptionsSize
+        allocaBytes (fromIntegral size) $ \p -> do
+          FFI.initializeMCJITCompilerOptions p size
+          traverse_ (FFI.setMCJITCompilerOptionsOptLevel p <=< encodeM) opt
+          traverse_ (FFI.setMCJITCompilerOptionsCodeModel p <=< encodeM) cm
+          traverse_ (FFI.setMCJITCompilerOptionsNoFramePointerElim p <=< encodeM) fpe
+          traverse_ (FFI.setMCJITCompilerOptionsEnableFastISel p <=< encodeM) fisel
+          FFI.createMCJITCompilerForModule e m p size s
+  t <- newIORef (Deferred $ \mod f -> do m' <- readModule mod
+                                         withExecutionEngine c (Just m') createMCJITCompilerForModule f)
+  f (MCJIT t)
+
+instance ExecutionEngine MCJIT (FunPtr ()) where
+  withModuleInEngine (MCJIT s) m f = do
+    jitState <- readIORef s
+    let f' (ExecutableModule _ m) = f (ExecutableModule (MCJIT s) m)
+    case jitState of
+      Deferred c -> c m $ \e -> 
+        bracket_ 
+         (writeIORef s (Constructed e))
+         (writeIORef s jitState)
+         (withModuleInEngine e m f')
+      Constructed e -> withModuleInEngine e m f'
+
+  getFunction (ExecutableModule (MCJIT r) m) n = do
+    s <- liftIO $ readIORef r
+    case s of
+      Deferred _ -> return Nothing
+      Constructed e -> getFunction (ExecutableModule e m) n
diff --git a/src/LLVM/Internal/FFI/Analysis.h b/src/LLVM/Internal/FFI/Analysis.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Analysis.h
@@ -0,0 +1,11 @@
+#ifndef __LLVM_INTERNAL_FFI__ANALYSIS__H__
+#define __LLVM_INTERNAL_FFI__ANALYSIS__H__
+
+#include "llvm-c/Analysis.h"
+
+#define LLVM_HS_FOR_EACH_VERIFIER_FAILURE_ACTION(macro) \
+	macro(AbortProcess) \
+	macro(PrintMessage) \
+	macro(ReturnStatus)
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Analysis.hs b/src/LLVM/Internal/FFI/Analysis.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Analysis.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.Analysis where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.Module
+
+foreign import ccall unsafe "LLVMVerifyModule" verifyModule ::
+  Ptr Module -> VerifierFailureAction -> Ptr (OwnerTransfered CString) -> IO LLVMBool
diff --git a/src/LLVM/Internal/FFI/Assembly.hs b/src/LLVM/Internal/FFI/Assembly.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Assembly.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+-- | Functions to read and write textual LLVM assembly
+module LLVM.Internal.FFI.Assembly where
+
+import LLVM.Prelude
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.MemoryBuffer
+import LLVM.Internal.FFI.Module
+import LLVM.Internal.FFI.PtrHierarchy
+
+import Foreign.C
+import Foreign.Ptr
+
+-- | Use LLVM's parser to parse a string of llvm assembly in a memory buffer to get a module
+foreign import ccall unsafe "LLVM_Hs_ParseLLVMAssembly" parseLLVMAssembly ::
+  Ptr Context -> OwnerTransfered (Ptr MemoryBuffer) -> Ptr (OwnerTransfered CString) -> IO (Ptr Module)
+
+
+-- | LLVM's serializer to generate a string of llvm assembly from a module
+foreign import ccall unsafe "LLVM_Hs_WriteLLVMAssembly" writeLLVMAssembly ::
+  Ptr Module -> Ptr RawOStream -> IO ()
diff --git a/src/LLVM/Internal/FFI/AssemblyC.cpp b/src/LLVM/Internal/FFI/AssemblyC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/AssemblyC.cpp
@@ -0,0 +1,28 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "llvm-c/Core.h"
+#include "llvm-c/IRReader.h"
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMModuleRef LLVM_Hs_ParseLLVMAssembly(LLVMContextRef context,
+                                             LLVMMemoryBufferRef memoryBuffer,
+                                             char **error) {
+  LLVMModuleRef M;
+  LLVMParseIRInContext(context, memoryBuffer, &M, error);
+  return M;
+}
+
+void LLVM_Hs_WriteLLVMAssembly(LLVMModuleRef module, raw_ostream &os) {
+  os << *unwrap(module);
+}
+}
diff --git a/src/LLVM/Internal/FFI/Attribute.h b/src/LLVM/Internal/FFI/Attribute.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Attribute.h
@@ -0,0 +1,90 @@
+#ifndef __LLVM_INTERNAL_FFI__ATTRIBUTES__H__
+#define __LLVM_INTERNAL_FFI__ATTRIBUTES__H__
+
+
+// The last three arguments are flags indicating if this is a
+// parameter attribute, function result attribute or function attribute.
+#define LLVM_HS_FOR_EACH_ATTRIBUTE_KIND(macro)	\
+  macro(None,F,F,F)                                 \
+  macro(AlwaysInline,F,F,T)                         \
+  macro(ArgMemOnly,F,F,T)                           \
+  macro(Builtin,F,F,T)                              \
+  macro(Cold,F,F,T)                                 \
+  macro(Convergent,F,F,T)                           \
+  macro(Hot,F,F,T)                                  \
+  macro(ImmArg,T,F,F)                               \
+  macro(InAlloca,T,F,F)                             \
+  macro(InReg,T,T,F)                                \
+  macro(InaccessibleMemOnly,F,F,T)                  \
+  macro(InaccessibleMemOrArgMemOnly,F,F,T)          \
+  macro(InlineHint,F,F,T)                           \
+  macro(JumpTable,F,F,T)                            \
+  macro(MinSize,F,F,T)                              \
+  macro(Naked,F,F,T)                                \
+  macro(Nest,T,F,F)                                 \
+  macro(NoAlias,T,T,F)                              \
+  macro(NoBuiltin,F,F,T)                            \
+  macro(NoCallback,F,F,T)                           \
+  macro(NoCapture,T,F,F)                            \
+  macro(NoCfCheck,F,F,T)                            \
+  macro(NoDuplicate,F,F,T)                          \
+  macro(NoFree,T,F,T)                               \
+  macro(NoImplicitFloat,F,F,T)                      \
+  macro(NoInline,F,F,T)                             \
+  macro(NoMerge,F,F,T)                              \
+  macro(NoProfile,F,F,T)                            \
+  macro(NoRecurse,F,F,T)                            \
+  macro(NoRedZone,F,F,T)                            \
+  macro(NoReturn,F,F,T)                             \
+  macro(NoSync,F,F,T)                               \
+  macro(NoUndef,F,F,T)                              \
+  macro(NoUnwind,F,F,T)                             \
+  macro(NonLazyBind,F,F,T)                          \
+  macro(NonNull,T,T,F)                              \
+  macro(NullPointerIsValid,T,T,F)                   \
+  macro(OptForFuzzing,F,F,T)                        \
+  macro(OptimizeForSize,F,F,T)                      \
+  macro(OptimizeNone,F,F,T)                         \
+  macro(ReadNone,T,F,T)                             \
+  macro(ReadOnly,T,F,T)                             \
+  macro(Returned,T,F,F)                             \
+  macro(ReturnsTwice,F,F,T)                         \
+  macro(SExt,T,T,F)                                 \
+  macro(SafeStack,F,F,T)                            \
+  macro(SanitizeAddress,F,F,T)                      \
+  macro(SanitizeHWAddress,F,F,T)                    \
+  macro(SanitizeMemTag,F,F,T)                       \
+  macro(SanitizeMemory,F,F,T)                       \
+  macro(SanitizeThread,F,F,T)                       \
+  macro(ShadowCallStack,F,F,T)                      \
+  macro(Speculatable,F,F,T)                         \
+  macro(SpeculativeLoadHardening,F,F,T)             \
+  macro(StackProtect,F,F,T)                         \
+  macro(StackProtectReq,F,F,T)                      \
+  macro(StackProtectStrong,F,F,T)                   \
+  macro(StrictFP,F,F,T)                             \
+  macro(SwiftError,T,F,F)                           \
+  macro(SwiftSelf,T,F,F)                            \
+  macro(UWTable,F,F,T)                              \
+  macro(WillReturn,F,F,T)                           \
+  macro(WriteOnly,T,F,T)                            \
+  macro(ZExt,T,T,F)                                 \
+  macro(ByRef,T,F,F)                                \
+  macro(ByVal,T,F,F)                                \
+  macro(MustProgress,F,F,T)                         \
+  macro(Preallocated,F,F,T)                         \
+  macro(StructRet,T,F,F)                            \
+  macro(Alignment,T,T,F)                            \
+  macro(AllocSize,F,F,T)                            \
+  macro(Dereferenceable,T,T,F)                      \
+  macro(DereferenceableOrNull,T,T,F)                \
+  macro(StackAlignment,F,F,T)                       \
+  macro(EndAttrKinds,F,F,F)
+
+typedef enum {
+#define ENUM_CASE(x,p,r,f) LLVM_Hs_AttributeKind_ ## x,
+LLVM_HS_FOR_EACH_ATTRIBUTE_KIND(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_AttributeKind;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Attribute.hs b/src/LLVM/Internal/FFI/Attribute.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Attribute.hs
@@ -0,0 +1,169 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  RankNTypes
+  #-}
+module LLVM.Internal.FFI.Attribute where
+
+import LLVM.Prelude
+
+import Foreign.C
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.LLVMCTypes
+
+type Slot = CUInt
+type IntValue = Word64
+
+{-
+Data model:
+llvm::Attribute is one function or parameter attribute
+
+llvm::AttributeSet stores a set of function, return or parameter attributes
+
+llvm::AttributeList stores the AttributeSet for the function itself,
+the return value and for the functions parameters.
+
+Encode path:
+Use AttrBuilder on the C++ side only, to implement [Attribute] -> AttributeList
+AttributeLists -> whole AttributeList
+-}
+
+data MixedAttributeType
+data FunctionAttributeType
+data ParameterAttributeType
+data AttributeImpl a
+data AttributeSetImpl a
+data AttributeListImpl
+
+type Attribute a = Ptr (AttributeImpl a)
+type FunctionAttribute = Attribute FunctionAttributeType
+type ParameterAttribute = Attribute ParameterAttributeType
+newtype AttributeIndex = AttributeIndex CUInt
+
+type AttributeSet a = Ptr (AttributeSetImpl a)
+-- type MixedAttributeSet = AttributeSet MixedAttributeType
+type FunctionAttributeSet = AttributeSet FunctionAttributeType
+type ParameterAttributeSet = AttributeSet ParameterAttributeType
+type AttributeList = Ptr AttributeListImpl
+
+forgetAttributeType :: AttributeSet a -> AttributeSet MixedAttributeType
+forgetAttributeType = castPtr
+
+functionIndex :: AttributeIndex
+functionIndex = AttributeIndex (-1)
+returnIndex :: AttributeIndex
+returnIndex = AttributeIndex 0
+
+data AttrSetDecoder a = AttrSetDecoder {
+    attrSetDecoderAttributesAtIndex :: forall b. a -> AttributeIndex -> IO (AttributeSet b),
+    attrSetDecoderCountParams :: a -> IO CUInt
+  }
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreContext.html#ga08d1304979a5ea706b1641c11937b80d>
+foreign import ccall unsafe "LLVMGetEnumAttributeKind" parameterAttributeKindAsEnum ::
+  ParameterAttribute -> IO ParameterAttributeKind
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreContext.html#ga08d1304979a5ea706b1641c11937b80d>
+foreign import ccall unsafe "LLVMGetEnumAttributeKind" functionAttributeKindAsEnum ::
+  FunctionAttribute -> IO FunctionAttributeKind
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreContext.html#gab835d65835c777cd435e5502da143564>
+foreign import ccall unsafe "LLVMIsStringAttribute" isStringAttribute ::
+  Attribute a -> IO LLVMBool
+
+-- | Unfortunately the LLVM C API function can only deal with a 32 bit (unsigned*) length, so we can't just call
+-- | <https://llvm.org/doxygen/group__LLVMCCoreContext.html#gab88856ea2394e46b10c145aa095e0c06>
+foreign import ccall unsafe "LLVM_Hs_AttributeKindAsString" attributeKindAsString ::
+  Attribute a -> Ptr CSize -> IO (Ptr CChar)
+
+-- | Unfortunately the LLVM C API function can only deal with a 32 bit (unsigned*) length, so we can't just call
+-- | <https://llvm.org/doxygen/group__LLVMCCoreContext.html#ga6d78aed2879dccec9d81a1acfad170fd
+foreign import ccall unsafe "LLVM_Hs_AttributeValueAsString" attributeValueAsString ::
+  Attribute a -> Ptr CSize -> IO (Ptr CChar)
+
+-- TODO-LLVM-VERSION-INCREASE: Check C API coverage (has this functionality been added?)
+-- | The LLVM C API does not expose this functionality
+foreign import ccall unsafe "LLVM_Hs_AttributeValueAsInt" attributeValueAsInt ::
+  Attribute a -> IO Word64
+
+-- | The LLVM C API does not expose this functionality
+foreign import ccall unsafe "LLVM_Hs_getNumAttributes" getNumAttributes ::
+  AttributeSet a -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_getAttributes" getAttributes ::
+  AttributeSet a -> Ptr (Attribute a) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetAttributeList" getAttributeList ::
+  Ptr Context -> AttributeIndex -> AttributeSet a -> IO AttributeList
+
+foreign import ccall unsafe "LLVM_Hs_BuildAttributeList" buildAttributeList ::
+  Ptr Context -> FunctionAttributeSet -> ParameterAttributeSet -> Ptr ParameterAttributeSet -> CUInt -> IO AttributeList
+
+foreign import ccall unsafe "LLVM_Hs_DisposeAttributeList" disposeAttributeList ::
+  AttributeList -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetAttributeSet" getAttributeSet ::
+  Ptr Context -> Ptr (AttrBuilder a) -> IO (AttributeSet a)
+
+foreign import ccall unsafe "LLVM_Hs_DisposeAttributeSet" disposeAttributeSet ::
+  AttributeSet a -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttributeSetsEqual" attributeSetsEqual ::
+  AttributeSet a -> AttributeSet a -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_AttributeSetHasAttributes" attributeSetHasAttributes ::
+  AttributeSet a -> IO LLVMBool
+
+data AttrBuilder a
+type FunctionAttrBuilder = AttrBuilder FunctionAttributeType
+type ParameterAttrBuilder = AttrBuilder ParameterAttributeType
+
+foreign import ccall unsafe "LLVM_Hs_GetAttrBuilderSize" getAttrBuilderSize ::
+  CSize
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderFromAttrSet" attrBuilderFromSet ::
+  AttributeSet a -> IO (Ptr (AttrBuilder a))
+
+foreign import ccall unsafe "LLVM_Hs_DisposeAttrBuilder" disposeAttrBuilder ::
+  Ptr (AttrBuilder a) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderMerge" mergeAttrBuilder ::
+  Ptr (AttrBuilder a) -> Ptr (AttrBuilder a) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_ConstructAttrBuilder" constructAttrBuilder ::
+  Ptr Word8 -> IO (Ptr (AttrBuilder a))
+
+foreign import ccall unsafe "LLVM_Hs_DestroyAttrBuilder" destroyAttrBuilder ::
+  Ptr (AttrBuilder a) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddAttributeKind" attrBuilderAddFunctionAttributeKind ::
+  Ptr FunctionAttrBuilder -> FunctionAttributeKind -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddAttributeKind" attrBuilderAddParameterAttributeKind ::
+  Ptr ParameterAttrBuilder -> ParameterAttributeKind -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddStringAttribute" attrBuilderAddStringAttribute ::
+  Ptr (AttrBuilder a) -> Ptr CChar -> CSize -> Ptr CChar -> CSize -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddAlignment" attrBuilderAddAlignment ::
+  Ptr ParameterAttrBuilder -> Word64 -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddStackAlignment" attrBuilderAddStackAlignment ::
+  Ptr FunctionAttrBuilder -> Word64 -> IO ()
+
+-- The CInt is 0 if the last value is null and 1 otherwise
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddAllocSize" attrBuilderAddAllocSize' ::
+  Ptr FunctionAttrBuilder -> CUInt -> CUInt -> LLVMBool -> IO ()
+
+attrBuilderAddAllocSize :: Ptr FunctionAttrBuilder -> CUInt -> (CUInt, LLVMBool) -> IO ()
+attrBuilderAddAllocSize b i (y, isJust) = attrBuilderAddAllocSize' b i y isJust
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddDereferenceableAttr" attrBuilderAddDereferenceable ::
+  Ptr ParameterAttrBuilder -> Word64 -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttrBuilderAddDereferenceableOrNullAttr" attrBuilderAddDereferenceableOrNull ::
+  Ptr ParameterAttrBuilder -> Word64 -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_AttributeGetAllocSizeArgs" attributeGetAllocSizeArgs ::
+  FunctionAttribute -> Ptr CUInt -> Ptr CUInt -> IO LLVMBool
diff --git a/src/LLVM/Internal/FFI/AttributeC.cpp b/src/LLVM/Internal/FFI/AttributeC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/AttributeC.cpp
@@ -0,0 +1,154 @@
+#define __STDC_LIMIT_MACROS
+#include "LLVM/Internal/FFI/AttributeC.hpp"
+#include "llvm/IR/LLVMContext.h"
+
+extern "C" {
+
+static_assert(sizeof(AttributeList) == sizeof(AttributeListImpl *),
+              "AttributeList implementation has changed");
+
+static_assert(sizeof(Attribute) == sizeof(AttributeImpl *),
+              "Attribute implementation has changed");
+
+#define CHECK(name, p, r, f)                                                   \
+    static_assert(unsigned(llvm::Attribute::name) ==                           \
+                      unsigned(LLVM_Hs_AttributeKind_##name),                  \
+                  "LLVM_Hs_AttributeKind enum out of sync w/ "                 \
+                  "llvm::Attribute::AttrKind for " #name);
+LLVM_HS_FOR_EACH_ATTRIBUTE_KIND(CHECK)
+#undef CHECK
+
+uint64_t LLVM_Hs_AttributeValueAsInt(LLVMAttributeRef a) {
+    return unwrap(a).getValueAsInt();
+}
+
+const char *LLVM_Hs_AttributeKindAsString(LLVMAttributeRef a, size_t &l) {
+    const StringRef s = unwrap(a).getKindAsString();
+    l = s.size();
+    return s.data();
+}
+
+const char *LLVM_Hs_AttributeValueAsString(LLVMAttributeRef a, size_t &l) {
+    const StringRef s = unwrap(a).getValueAsString();
+    l = s.size();
+    return s.data();
+}
+
+AttributeList * LLVM_Hs_GetAttributeList(LLVMContextRef context,
+                                         unsigned index,
+                                         AttributeSet *as) {
+    return new AttributeList(AttributeList::get(*unwrap(context), index, *as));
+}
+
+AttributeList * LLVM_Hs_BuildAttributeList(LLVMContextRef context,
+                                           AttributeSet *fAttrs,
+                                           AttributeSet *rAttrs,
+                                           AttributeSet **pAttrs,
+                                           unsigned numPAttrs) {
+    std::vector<AttributeSet> pAttrSets{numPAttrs};
+    for (unsigned i = 0; i < numPAttrs; ++i) {
+        pAttrSets[i] = *pAttrs[i];
+    }
+    return new AttributeList(
+        AttributeList::get(*unwrap(context), *fAttrs, *rAttrs, pAttrSets));
+}
+
+void LLVM_Hs_DisposeAttributeList(AttributeList *attributeList) {
+    delete attributeList;
+}
+
+AttributeSet *LLVM_Hs_GetAttributeSet(LLVMContextRef context,
+                                      const AttrBuilder &ab) {
+    return new AttributeSet(AttributeSet::get(*unwrap(context), ab));
+}
+
+void LLVM_Hs_DisposeAttributeSet(AttributeList *attributeList) {
+    delete attributeList;
+}
+
+LLVMBool LLVM_Hs_AttributeSetsEqual(AttributeSet *as1,
+                                    AttributeSet *as2) {
+    return *as1 == *as2;
+}
+
+LLVMBool LLVM_Hs_AttributeSetHasAttributes(AttributeSet *as) {
+    return as->hasAttributes();
+}
+
+unsigned LLVM_Hs_getNumAttributes(AttributeSet *attributeSet) {
+    return attributeSet->getNumAttributes();
+}
+
+void LLVM_Hs_getAttributes(AttributeSet *attributeSet,
+                           LLVMAttributeRef *attrs) {
+    for (auto a : *attributeSet) {
+        *attrs++ = wrap(a);
+    }
+}
+
+size_t LLVM_Hs_GetAttrBuilderSize() { return sizeof(AttrBuilder); }
+
+AttrBuilder *LLVM_Hs_ConstructAttrBuilder(char *p) {
+    return new (p) AttrBuilder();
+}
+
+AttrBuilder *LLVM_Hs_AttrBuilderFromAttrSet(AttributeSet *as) {
+    return new AttrBuilder(*as);
+}
+
+void LLVM_Hs_DisposeAttrBuilder(AttributeSet *as) { delete as; }
+
+void LLVM_Hs_AttrBuilderMerge(AttrBuilder *ab1, AttrBuilder *ab2) {
+    ab1->merge(*ab2);
+}
+
+void LLVM_Hs_DestroyAttrBuilder(AttrBuilder *a) { a->~AttrBuilder(); }
+
+void LLVM_Hs_AttrBuilderAddAttributeKind(AttrBuilder &ab, unsigned kind) {
+    ab.addAttribute(Attribute::AttrKind(kind));
+}
+
+void LLVM_Hs_AttrBuilderAddStringAttribute(AttrBuilder &ab, const char *kind,
+                                           size_t kind_len, const char *value,
+                                           size_t value_len) {
+    ab.addAttribute(StringRef(kind, kind_len), StringRef(value, value_len));
+}
+
+void LLVM_Hs_AttrBuilderAddAlignment(AttrBuilder &ab, uint64_t v) {
+    ab.addAlignmentAttr(MaybeAlign(v));
+}
+
+void LLVM_Hs_AttrBuilderAddStackAlignment(AttrBuilder &ab, uint64_t v) {
+    ab.addStackAlignmentAttr(MaybeAlign(v));
+}
+
+void LLVM_Hs_AttrBuilderAddAllocSize(AttrBuilder &ab, unsigned x, unsigned y,
+                                     LLVMBool optionalIsThere) {
+    if (optionalIsThere) {
+        ab.addAllocSizeAttr(x, Optional<unsigned>(y));
+    } else {
+        ab.addAllocSizeAttr(x, Optional<unsigned>());
+    }
+}
+
+void LLVM_Hs_AttrBuilderAddDereferenceableAttr(AttrBuilder &ab, uint64_t v) {
+    ab.addDereferenceableAttr(v);
+}
+
+void LLVM_Hs_AttrBuilderAddDereferenceableOrNullAttr(AttrBuilder &ab,
+                                                     uint64_t v) {
+    ab.addDereferenceableOrNullAttr(v);
+}
+
+LLVMBool LLVM_Hs_AttributeGetAllocSizeArgs(LLVMAttributeRef a, unsigned *x,
+                                           unsigned *y) {
+    auto pair = unwrap(a).getAllocSizeArgs();
+    *x = pair.first;
+    if (pair.second.hasValue()) {
+        *y = pair.second.getValue();
+        return 1;
+    } else {
+        return 0;
+    }
+}
+}
diff --git a/src/LLVM/Internal/FFI/AttributeC.hpp b/src/LLVM/Internal/FFI/AttributeC.hpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/AttributeC.hpp
@@ -0,0 +1,11 @@
+#ifndef __LLVM_ATTRIBUTE_C_HPP__
+#define __LLVM_ATTRIBUTE_C_HPP__
+#define __STDC_LIMIT_MACROS
+#include "LLVM/Internal/FFI/Attribute.h"
+#include "llvm/IR/Attributes.h"
+using namespace llvm;
+
+typedef AttributeSet *LLVMAttributeSetRef;
+typedef AttributeList *LLVMAttributeListRef;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/BasicBlock.hs b/src/LLVM/Internal/FFI/BasicBlock.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/BasicBlock.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses
+  #-}
+
+-- | <http://llvm.org/doxygen/classllvm_1_1BasicBlock.html>
+module LLVM.Internal.FFI.BasicBlock where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.PtrHierarchy
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueBasicBlock.html#gab57c996ff697ef40966432055ae47a4e>
+foreign import ccall unsafe "LLVMIsABasicBlock" isABasicBlock ::
+    Ptr Value -> IO (Ptr BasicBlock)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueBasicBlock.html#ga754e45f69f4b784b658d9e379943f354>
+foreign import ccall unsafe "LLVMGetBasicBlockTerminator" getBasicBlockTerminator ::
+    Ptr BasicBlock -> IO (Ptr Instruction)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueBasicBlock.html#ga9baf824cd325ad211027b23fce8a7494>
+foreign import ccall unsafe "LLVMGetFirstInstruction" getFirstInstruction ::
+    Ptr BasicBlock -> IO (Ptr Instruction)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueBasicBlock.html#gaa0bb2c95802d06bf94f4c55e61fc3477>
+foreign import ccall unsafe "LLVMGetLastInstruction" getLastInstruction ::
+    Ptr BasicBlock -> IO (Ptr Instruction)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueInstruction.html#ga1b4c3bd197e86e8bffdda247ddf8ec5e>
+foreign import ccall unsafe "LLVMGetNextInstruction" getNextInstruction ::
+    Ptr Instruction -> IO (Ptr Instruction)
+
diff --git a/src/LLVM/Internal/FFI/BinaryOperator.hs b/src/LLVM/Internal/FFI/BinaryOperator.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/BinaryOperator.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM BinaryOperator class
+module LLVM.Internal.FFI.BinaryOperator where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.LLVMCTypes
+
+foreign import ccall unsafe "LLVMIsABinaryOperator" isABinaryOperator ::
+    Ptr Value -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_HasNoSignedWrap" hasNoSignedWrap ::
+    Ptr Value -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_HasNoUnsignedWrap" hasNoUnsignedWrap ::
+    Ptr Value -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_IsExact" isExact ::
+    Ptr Value -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetFastMathFlags" getFastMathFlags ::
+    Ptr Value -> IO FastMathFlags
diff --git a/src/LLVM/Internal/FFI/Bitcode.hs b/src/LLVM/Internal/FFI/Bitcode.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Bitcode.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+-- | Functions to read and write LLVM bitcode
+module LLVM.Internal.FFI.Bitcode where
+
+import LLVM.Prelude
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.MemoryBuffer
+import LLVM.Internal.FFI.Module
+import LLVM.Internal.FFI.PtrHierarchy
+
+import Foreign.C
+import Foreign.Ptr
+
+foreign import ccall unsafe "LLVM_Hs_ParseBitcode" parseBitcode ::
+  Ptr Context -> Ptr MemoryBuffer -> Ptr (OwnerTransfered CString) -> IO (Ptr Module)
+
+foreign import ccall unsafe "LLVM_Hs_WriteBitcode" writeBitcode ::
+  Ptr Module -> Ptr RawOStream -> IO ()
+
+                               
+
diff --git a/src/LLVM/Internal/FFI/BitcodeC.cpp b/src/LLVM/Internal/FFI/BitcodeC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/BitcodeC.cpp
@@ -0,0 +1,34 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm-c/Core.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMModuleRef LLVM_Hs_ParseBitcode(
+	LLVMContextRef c,
+	LLVMMemoryBufferRef mb,
+	char **error
+) {
+    Expected<std::unique_ptr<Module>> moduleOrErr = parseBitcodeFile(unwrap(mb)->getMemBufferRef(), *unwrap(c));
+    if (Error err = moduleOrErr.takeError()) {
+        handleAllErrors(std::move(err), [&](ErrorInfoBase &eib) {
+                *error = strdup(eib.message().c_str());
+            });
+        return nullptr;
+    }
+    return wrap(moduleOrErr.get().release());
+}
+
+void LLVM_Hs_WriteBitcode(LLVMModuleRef m, raw_ostream &os) {
+	WriteBitcodeToFile(*unwrap(m), os);
+}
+
+}
+
diff --git a/src/LLVM/Internal/FFI/Builder.hs b/src/LLVM/Internal/FFI/Builder.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Builder.hs
@@ -0,0 +1,257 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module LLVM.Internal.FFI.Builder where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+import GHC.Stack
+
+import qualified Data.List as List
+import qualified Data.Map as Map
+
+import qualified LLVM.AST.Instruction as A
+import LLVM.Internal.InstructionDefs as ID
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+data Builder
+
+foreign import ccall unsafe "LLVMCreateBuilderInContext" createBuilderInContext ::
+  Ptr Context -> IO (Ptr Builder)
+
+foreign import ccall unsafe "LLVMDisposeBuilder" disposeBuilder ::
+  Ptr Builder -> IO ()
+
+foreign import ccall unsafe "LLVMPositionBuilderAtEnd" positionBuilderAtEnd ::
+  Ptr Builder -> Ptr BasicBlock -> IO ()
+
+foreign import ccall unsafe "LLVMBuildRet" buildRet ::
+  Ptr Builder -> Ptr Value -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildBr" buildBr ::
+  Ptr Builder -> Ptr BasicBlock -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildCondBr" buildCondBr ::
+  Ptr Builder -> Ptr Value -> Ptr BasicBlock -> Ptr BasicBlock -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildSwitch" buildSwitch ::
+  Ptr Builder -> Ptr Value -> Ptr BasicBlock -> CUInt -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildIndirectBr" buildIndirectBr ::
+  Ptr Builder -> Ptr Value -> CUInt -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildInvoke" buildInvoke ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt
+              -> Ptr BasicBlock -> Ptr BasicBlock -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildResume" buildResume ::
+  Ptr Builder -> Ptr Value -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildUnreachable" buildUnreachable ::
+  Ptr Builder -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildCleanupRet" buildCleanupRet ::
+  Ptr Builder -> Ptr Value -> Ptr BasicBlock -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildCatchRet" buildCatchRet ::
+  Ptr Builder -> Ptr Value -> Ptr BasicBlock -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildCatchSwitch" buildCatchSwitch ::
+  Ptr Builder -> Ptr Value -> Ptr BasicBlock -> CUInt -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildAdd" buildAdd ::
+  Ptr Builder -> LLVMBool -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildMul" buildMul ::
+  Ptr Builder -> LLVMBool -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildShl" buildShl ::
+  Ptr Builder -> LLVMBool -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSub" buildSub ::
+  Ptr Builder -> LLVMBool -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildUDiv" buildUDiv ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSDiv" buildSDiv ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildLShr" buildLShr ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildAShr" buildAShr ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildAddrSpaceCast" buildAddrSpaceCast ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildBitCast" buildBitCast ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFPExt" buildFPExt ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFPToSI" buildFPToSI ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFPToUI" buildFPToUI ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFPTrunc" buildFPTrunc ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildIntToPtr" buildIntToPtr ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildPtrToInt" buildPtrToInt ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSExt" buildSExt ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSIToFP" buildSIToFP ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildTrunc" buildTrunc ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildUIToFP" buildUIToFP ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildZExt" buildZExt ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildAnd" buildAnd ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildOr" buildOr ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSRem" buildSRem ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildURem" buildURem ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildXor" buildXor ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFNeg" buildFNeg ::
+  Ptr Builder -> Ptr Value -> CString -> IO (Ptr UnaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFAdd" buildFAdd ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFDiv" buildFDiv ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFMul" buildFMul ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFRem" buildFRem ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFSub" buildFSub ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr BinaryOperator)
+
+foreign import ccall unsafe "LLVMBuildArrayAlloca" buildAlloca ::
+  Ptr Builder -> Ptr Type -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildLoad" buildLoad' ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> MemoryOrdering -> SynchronizationScope -> CUInt -> CString -> IO (Ptr Instruction)
+
+buildLoad :: Ptr Builder -> LLVMBool -> Ptr Value -> (SynchronizationScope, MemoryOrdering) -> CUInt -> CString -> IO (Ptr Instruction)
+buildLoad builder vol a' (ss, mo) al s = buildLoad' builder vol a' mo ss al s
+
+foreign import ccall unsafe "LLVM_Hs_BuildStore" buildStore' ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> MemoryOrdering -> SynchronizationScope -> CUInt -> CString -> IO (Ptr Instruction)
+
+buildStore :: Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> (SynchronizationScope, MemoryOrdering) -> CUInt -> CString -> IO (Ptr Instruction)
+buildStore builder vol a' v' (ss, mo) al s = buildStore' builder vol a' v' mo ss al s
+
+foreign import ccall unsafe "LLVM_Hs_BuildGEP" buildGetElementPtr' ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildInBoundsGEP" buildInBoundsGetElementPtr' ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt -> CString -> IO (Ptr Instruction)
+
+buildGetElementPtr :: HasCallStack => Ptr Builder -> LLVMBool -> Ptr Value -> (CUInt, Ptr (Ptr Value)) -> CString -> IO (Ptr Instruction)
+buildGetElementPtr builder (LLVMBool 1) a (n, is) s = buildInBoundsGetElementPtr' builder a is n s
+buildGetElementPtr builder (LLVMBool 0) a (n, is) s = buildGetElementPtr' builder a is n s
+buildGetElementPtr _ (LLVMBool i) _ _ _ = error ("LLVMBool should be 0 or 1 but is " <> show i)
+
+foreign import ccall unsafe "LLVM_Hs_BuildFence" buildFence' ::
+  Ptr Builder -> MemoryOrdering -> SynchronizationScope -> CString -> IO (Ptr Instruction)
+
+buildFence :: Ptr Builder -> (SynchronizationScope, MemoryOrdering) -> CString -> IO (Ptr Instruction)
+buildFence builder (ss, mo) s = buildFence' builder mo ss s
+
+foreign import ccall unsafe "LLVM_Hs_BuildAtomicCmpXchg" buildCmpXchg' ::
+  Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> Ptr Value -> MemoryOrdering -> MemoryOrdering -> SynchronizationScope -> CString -> IO (Ptr Instruction)
+
+buildCmpXchg :: Ptr Builder -> LLVMBool -> Ptr Value -> Ptr Value -> Ptr Value -> (SynchronizationScope, MemoryOrdering) -> MemoryOrdering -> CString -> IO (Ptr Instruction)
+buildCmpXchg builder vol a e r (ss, smo) fmo s =  buildCmpXchg' builder vol a e r smo fmo ss s
+
+foreign import ccall unsafe "LLVM_Hs_BuildAtomicRMW" buildAtomicRMW' ::
+  Ptr Builder -> LLVMBool -> RMWOperation -> Ptr Value -> Ptr Value -> MemoryOrdering -> SynchronizationScope -> CString -> IO (Ptr Instruction)
+
+buildAtomicRMW :: Ptr Builder -> LLVMBool -> RMWOperation -> Ptr Value -> Ptr Value -> (SynchronizationScope, MemoryOrdering) -> CString -> IO (Ptr Instruction)
+buildAtomicRMW builder vol rmwOp a v (ss, mo) s = buildAtomicRMW' builder vol rmwOp a v mo ss s
+
+foreign import ccall unsafe "LLVM_Hs_BuildICmp" buildICmp ::
+  Ptr Builder -> ICmpPredicate -> Ptr Value -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildFCmp" buildFCmp ::
+  Ptr Builder -> FCmpPredicate -> Ptr Value -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildPhi" buildPhi ::
+  Ptr Builder -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildCall" buildCall ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildFreeze" buildFreeze ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildSelect" buildSelect ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildVAArg" buildVAArg ::
+  Ptr Builder -> Ptr Value -> Ptr Type -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildExtractElement" buildExtractElement ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildInsertElement" buildInsertElement ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> Ptr Value -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildShuffleVector" buildShuffleVector ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> Ptr CInt -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildExtractValue" buildExtractValue ::
+  Ptr Builder -> Ptr Value -> Ptr CUInt -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildInsertValue" buildInsertValue ::
+  Ptr Builder -> Ptr Value -> Ptr Value -> Ptr CUInt -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVMBuildLandingPad" buildLandingPad' ::
+  Ptr Builder -> Ptr Type -> Ptr Value -> CUInt -> CString -> IO (Ptr Instruction)
+
+-- | The personality should be set via the function
+buildLandingPad :: Ptr Builder -> Ptr Type -> CUInt -> CString -> IO (Ptr Instruction)
+buildLandingPad builder ty numClauses name = buildLandingPad' builder ty nullPtr numClauses name
+
+foreign import ccall unsafe "LLVM_Hs_BuildCleanupPad" buildCleanupPad ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_BuildCatchPad" buildCatchPad ::
+  Ptr Builder -> Ptr Value -> Ptr (Ptr Value) -> CUInt -> CString -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_SetFastMathFlags" setFastMathFlags ::
+  Ptr Builder -> FastMathFlags -> IO ()
diff --git a/src/LLVM/Internal/FFI/BuilderC.cpp b/src/LLVM/Internal/FFI/BuilderC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/BuilderC.cpp
@@ -0,0 +1,476 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/IRBuilder.h"
+
+#include "llvm-c/Core.h"
+
+#include "LLVM/Internal/FFI/Instruction.h"
+
+using namespace llvm;
+
+namespace llvm {
+static AtomicOrdering unwrap(LLVMAtomicOrdering l) {
+    switch(l) {
+        case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;
+        case LLVMAtomicOrderingUnordered: return AtomicOrdering::Unordered;
+        case LLVMAtomicOrderingMonotonic: return AtomicOrdering::Monotonic;
+        case LLVMAtomicOrderingAcquire: return AtomicOrdering::Acquire;
+        case LLVMAtomicOrderingRelease: return AtomicOrdering::Release;
+        case LLVMAtomicOrderingAcquireRelease:  return AtomicOrdering::AcquireRelease;
+        case LLVMAtomicOrderingSequentiallyConsistent: return AtomicOrdering::SequentiallyConsistent;
+        //FIXME: this function should be total and no default should be required
+        default: return AtomicOrdering(0);
+    }
+}
+
+static SyncScope::ID unwrap(LLVMSynchronizationScope l) {
+    switch(l) {
+        case LLVMSingleThreadSynchronizationScope: return SyncScope::SingleThread;
+        case LLVMSystemSynchronizationScope: return SyncScope::System;
+        //FIXME: this function should be total and no default should be required
+        default: return SyncScope::ID(0);
+    }
+}
+
+static AtomicRMWInst::BinOp unwrap(LLVMAtomicRMWBinOp_ l) {
+    switch(l) {
+#define ENUM_CASE(x) case LLVMAtomicRMWBinOp_ ## x: return AtomicRMWInst::x;
+LLVM_HS_FOR_EACH_RMW_OPERATION(ENUM_CASE)
+#undef ENUM_CASE
+    //FIXME: this function should be total and no default should be required
+    default: return AtomicRMWInst::BinOp(0);
+    }
+}
+
+static FastMathFlags unwrap(LLVMFastMathFlags f) {
+    FastMathFlags r = FastMathFlags();
+#define ENUM_CASE_F(x,l) if (f & LLVM ## x) r.set ## x();
+#define ENUM_CASE_T(x,l) if (f & LLVM ## x) r.set ## x(true);
+#define ENUM_CASE(x,l,takesArg) ENUM_CASE_ ## takesArg(x,l)
+LLVM_HS_FOR_EACH_FAST_MATH_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    return r;
+}
+
+}
+
+extern "C" {
+
+LLVMValueRef LLVM_Hs_BuildAdd(
+    LLVMBuilderRef b,
+    LLVMBool nsw,
+    LLVMBool nuw,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (nuw) {
+        return LLVMBuildNUWAdd(b, o0, o1, s);
+    } else if (nsw) {
+        return LLVMBuildNSWAdd(b, o0, o1, s);
+    } else {
+        return LLVMBuildAdd(b, o0, o1, s);
+    }
+}
+
+LLVMValueRef LLVM_Hs_BuildMul(
+    LLVMBuilderRef b,
+    LLVMBool nsw,
+    LLVMBool nuw,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (nuw) {
+        return LLVMBuildNUWMul(b, o0, o1, s);
+    } else if (nsw) {
+        return LLVMBuildNSWMul(b, o0, o1, s);
+    } else {
+        return LLVMBuildMul(b, o0, o1, s);
+    }
+}
+
+LLVMValueRef LLVM_Hs_BuildShl(
+    LLVMBuilderRef b,
+    LLVMBool nsw,
+    LLVMBool nuw,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    // TODO-LLVM-VERSION-INCREASE: Check C API coverage (has this functionality been added?)
+    // For some reason, the LLVM C API does not provide NUW/NSW constructors for Shl
+    BinaryOperator *BO = unwrap(b)->Insert(BinaryOperator::Create(Instruction::Shl, unwrap(o0), unwrap(o1)), s);
+    if (nuw) BO->setHasNoUnsignedWrap();
+    if (nsw) BO->setHasNoSignedWrap();
+    return wrap(BO);
+}
+
+LLVMValueRef LLVM_Hs_BuildSub(
+    LLVMBuilderRef b,
+    LLVMBool nsw,
+    LLVMBool nuw,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (nuw) {
+        return LLVMBuildNUWSub(b, o0, o1, s);
+    } else if (nsw) {
+        return LLVMBuildNSWSub(b, o0, o1, s);
+    } else {
+        return LLVMBuildSub(b, o0, o1, s);
+    }
+}
+
+LLVMValueRef LLVM_Hs_BuildUDiv(
+    LLVMBuilderRef b,
+    LLVMBool exact,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (!exact) {
+        return wrap(unwrap(b)->Insert(BinaryOperator::CreateUDiv(unwrap(o0), unwrap(o1)), s));
+    }
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateExactUDiv(unwrap(o0), unwrap(o1)), s));
+}
+
+LLVMValueRef LLVM_Hs_BuildSDiv(
+    LLVMBuilderRef b,
+    LLVMBool exact,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (!exact) {
+        return wrap(unwrap(b)->Insert(BinaryOperator::CreateSDiv(unwrap(o0), unwrap(o1)), s));
+    }
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateExactSDiv(unwrap(o0), unwrap(o1)), s));
+}
+
+LLVMValueRef LLVM_Hs_BuildLShr(
+    LLVMBuilderRef b,
+    LLVMBool exact,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (!exact) {
+        return wrap(unwrap(b)->Insert(BinaryOperator::CreateLShr(unwrap(o0), unwrap(o1)), s));
+    }
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateExactLShr(unwrap(o0), unwrap(o1)), s));
+}
+
+LLVMValueRef LLVM_Hs_BuildAShr(
+    LLVMBuilderRef b,
+    LLVMBool exact,
+    LLVMValueRef o0,
+    LLVMValueRef o1,
+    const char *s
+) {
+    if (!exact) {
+        return wrap(unwrap(b)->Insert(BinaryOperator::CreateAShr(unwrap(o0), unwrap(o1)), s));
+    }
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateExactAShr(unwrap(o0), unwrap(o1)), s));
+}
+
+LLVMValueRef LLVM_Hs_BuildAddrSpaceCast(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::AddrSpaceCast, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildBitCast(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::BitCast, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFPExt(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::FPExt, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFPToSI(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::FPToSI, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFPToUI(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::FPToUI, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFPTrunc(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::FPTrunc, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildIntToPtr(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::IntToPtr, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildPtrToInt(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::PtrToInt, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildSExt(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::SExt, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildSIToFP(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::SIToFP, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildTrunc(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::Trunc, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildUIToFP(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::UIToFP, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildZExt(LLVMBuilderRef b, LLVMValueRef val, LLVMTypeRef destTy, const char *name) {
+    return wrap(unwrap(b)->Insert(CastInst::Create(Instruction::ZExt, unwrap(val), unwrap(destTy)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildAnd(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateAnd(unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildOr(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateOr(unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildSRem(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateSRem(unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildURem(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateURem(unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildXor(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    return wrap(unwrap(b)->Insert(BinaryOperator::CreateXor(unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFNeg(LLVMBuilderRef b, LLVMValueRef rhs, const char *name) {
+    return LLVMBuildFNeg(b, rhs, name);
+}
+
+LLVMValueRef LLVM_Hs_BuildFAdd(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    BinaryOperator* bo = BinaryOperator::CreateFAdd(unwrap(lhs), unwrap(rhs));
+    bo->setFastMathFlags(unwrap(b)->getFastMathFlags());
+    return wrap(unwrap(b)->Insert(bo, name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFDiv(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    BinaryOperator* bo = BinaryOperator::CreateFDiv(unwrap(lhs), unwrap(rhs));
+    bo->setFastMathFlags(unwrap(b)->getFastMathFlags());
+    return wrap(unwrap(b)->Insert(bo, name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFMul(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    BinaryOperator* bo = BinaryOperator::CreateFMul(unwrap(lhs), unwrap(rhs));
+    bo->setFastMathFlags(unwrap(b)->getFastMathFlags());
+    return wrap(unwrap(b)->Insert(bo, name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFRem(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    BinaryOperator* bo = BinaryOperator::CreateFRem(unwrap(lhs), unwrap(rhs));
+    bo->setFastMathFlags(unwrap(b)->getFastMathFlags());
+    return wrap(unwrap(b)->Insert(bo, name));
+}
+
+LLVMValueRef LLVM_Hs_BuildFSub(LLVMBuilderRef b, LLVMValueRef lhs, LLVMValueRef rhs, const char *name) {
+    BinaryOperator* bo = BinaryOperator::CreateFSub(unwrap(lhs), unwrap(rhs));
+    bo->setFastMathFlags(unwrap(b)->getFastMathFlags());
+    return wrap(unwrap(b)->Insert(bo, name));
+}
+
+void LLVM_Hs_SetFastMathFlags(LLVMBuilderRef b, LLVMFastMathFlags f) {
+    unwrap(b)->setFastMathFlags(unwrap(f));
+}
+
+LLVMValueRef LLVM_Hs_BuildICmp(LLVMBuilderRef b, LLVMIntPredicate op, LLVMValueRef lhs, LLVMValueRef rhs, const char* name) {
+
+    return wrap(unwrap(b)->Insert(new ICmpInst(static_cast<ICmpInst::Predicate>(op),
+                                               unwrap(lhs), unwrap(rhs)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildLoad(
+    LLVMBuilderRef b,
+    LLVMBool isVolatile,
+    LLVMValueRef p,
+    LLVMAtomicOrdering atomicOrdering,
+    LLVMSynchronizationScope synchScope,
+    unsigned align,
+    const char *name
+) {
+    LoadInst *i = unwrap(b)->CreateAlignedLoad(unwrap(p), MaybeAlign(align), isVolatile, name);
+    i->setOrdering(unwrap(atomicOrdering));
+    if (atomicOrdering != LLVMAtomicOrderingNotAtomic) i->setSyncScopeID(unwrap(synchScope));
+    return wrap(i);
+}
+
+LLVMValueRef LLVM_Hs_BuildStore(
+    LLVMBuilderRef b,
+    LLVMBool isVolatile,
+    LLVMValueRef p,
+    LLVMValueRef v,
+    LLVMAtomicOrdering atomicOrdering,
+    LLVMSynchronizationScope synchScope,
+    unsigned align,
+    const char *name
+) {
+    StoreInst *i = unwrap(b)->CreateAlignedStore(unwrap(v), unwrap(p), MaybeAlign(align), isVolatile);
+    i->setName(name);
+    i->setOrdering(unwrap(atomicOrdering));
+    if (atomicOrdering != LLVMAtomicOrderingNotAtomic) i->setSyncScopeID(unwrap(synchScope));
+    return wrap(i);
+}
+
+LLVMValueRef LLVM_Hs_BuildFence(
+    LLVMBuilderRef b, LLVMAtomicOrdering lao, LLVMSynchronizationScope lss, const char *name
+) {
+    FenceInst *i = unwrap(b)->CreateFence(unwrap(lao), unwrap(lss));
+    i->setName(name);
+    return wrap(i);
+}
+
+LLVMValueRef LLVM_Hs_BuildAtomicCmpXchg(
+    LLVMBuilderRef b,
+    LLVMBool v,
+    LLVMValueRef ptr,
+    LLVMValueRef cmp,
+    LLVMValueRef n,
+    LLVMAtomicOrdering successOrdering,
+    LLVMAtomicOrdering failureOrdering,
+    LLVMSynchronizationScope lss,
+    const char *name
+) {
+    AtomicCmpXchgInst *a = unwrap(b)->CreateAtomicCmpXchg(
+        unwrap(ptr), unwrap(cmp), unwrap(n), unwrap(successOrdering), unwrap(failureOrdering), unwrap(lss)
+    );
+    a->setVolatile(v);
+    a->setName(name);
+    return wrap(a);
+}
+
+LLVMValueRef LLVM_Hs_BuildAtomicRMW(
+    LLVMBuilderRef b,
+    LLVMBool v,
+    LLVMAtomicRMWBinOp_ rmwOp,
+    LLVMValueRef ptr,
+    LLVMValueRef val,
+    LLVMAtomicOrdering lao,
+    LLVMSynchronizationScope lss,
+    const char *name
+) {
+    AtomicRMWInst *a = unwrap(b)->CreateAtomicRMW(
+        unwrap(rmwOp), unwrap(ptr), unwrap(val), unwrap(lao), unwrap(lss)
+    );
+    a->setVolatile(v);
+    a->setName(name);
+    return wrap(a);
+}
+
+LLVMValueRef LLVM_Hs_BuildCleanupPad(LLVMBuilderRef b, LLVMValueRef parentPad,
+                                     LLVMValueRef *args, unsigned numArgs,
+                                     const char *name) {
+  return wrap(unwrap(b)->CreateCleanupPad(unwrap(parentPad),
+                                          makeArrayRef(unwrap(args), numArgs),
+                                          name));
+}
+
+LLVMValueRef LLVM_Hs_BuildCatchPad(LLVMBuilderRef b, LLVMValueRef catchSwitch,
+                                   LLVMValueRef *args, unsigned numArgs,
+                                   const char *name) {
+    return wrap(unwrap(b)->CreateCatchPad(unwrap(catchSwitch),
+                                          makeArrayRef(unwrap(args), numArgs),
+                                          name));
+}
+
+LLVMValueRef LLVM_Hs_BuildCleanupRet(LLVMBuilderRef b, LLVMValueRef cleanupPad,
+                                     LLVMBasicBlockRef unwindDest) {
+    // Due to the way name resolution works in llvm-hs, cleanupPad might not
+    // actually be a CleanupPadInst. However, it will later be replaced by one.
+    // Pretending that we have one is thus ok here.
+    auto cleanupPad_ = static_cast<CleanupPadInst*>(unwrap<Value>(cleanupPad));
+    return wrap(unwrap(b)->CreateCleanupRet(cleanupPad_,
+                                            unwrap(unwindDest)));
+}
+
+LLVMValueRef LLVM_Hs_BuildCatchRet(LLVMBuilderRef b, LLVMValueRef catchPad,
+                                   LLVMBasicBlockRef successor) {
+    // Due to the way name resolution works in llvm-hs, catchPad might not
+    // actually be a CatchPadInst. However, it will later be replaced by one.
+    // Pretending that we have one is thus ok here.
+    auto catchPad_ = static_cast<CatchPadInst *>(unwrap<Value>(catchPad));
+    return wrap(unwrap(b)->CreateCatchRet(catchPad_, unwrap(successor)));
+}
+
+LLVMValueRef LLVM_Hs_BuildCatchSwitch(LLVMBuilderRef b, LLVMValueRef parentPad,
+                                      LLVMBasicBlockRef unwindDest,
+                                      unsigned numHandlers) {
+    return wrap(unwrap(b)->CreateCatchSwitch(unwrap(parentPad),
+                                             unwrap(unwindDest), numHandlers));
+}
+
+LLVMValueRef LLVM_Hs_BuildGEP(LLVMBuilderRef B, LLVMValueRef Pointer,
+                             LLVMValueRef *Indices, unsigned NumIndices,
+                             const char *Name) {
+  ArrayRef<Value *> IdxList(unwrap(Indices), NumIndices);
+  return wrap(unwrap(B)->Insert(GetElementPtrInst::Create(nullptr, unwrap(Pointer), IdxList), Name));
+}
+
+LLVMValueRef LLVM_Hs_BuildInBoundsGEP(LLVMBuilderRef B, LLVMValueRef Pointer,
+                                      LLVMValueRef *Indices, unsigned NumIndices,
+                                      const char *Name) {
+  ArrayRef<Value *> IdxList(unwrap(Indices), NumIndices);
+  return wrap(unwrap(B)->Insert(GetElementPtrInst::CreateInBounds(nullptr, unwrap(Pointer), IdxList), Name));
+}
+
+LLVMValueRef LLVM_Hs_BuildSelect(LLVMBuilderRef B, LLVMValueRef If,
+                                 LLVMValueRef Then, LLVMValueRef Else,
+                                 const char *Name) {
+    return wrap(unwrap(B)->Insert(SelectInst::Create(unwrap(If), unwrap(Then), unwrap(Else))));
+}
+
+LLVMValueRef LLVM_Hs_BuildExtractValue(
+    LLVMBuilderRef b,
+    LLVMValueRef a,
+    unsigned *idxs,
+    unsigned n,
+    const char *name
+) {
+    return wrap(unwrap(b)->Insert(ExtractValueInst::Create(unwrap(a), ArrayRef<unsigned>(idxs, n)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildInsertValue(
+    LLVMBuilderRef b,
+    LLVMValueRef a,
+    LLVMValueRef v,
+    unsigned *idxs,
+    unsigned n,
+    const char *name
+) {
+    return wrap(unwrap(b)->Insert(InsertValueInst::Create(unwrap(a), unwrap(v), ArrayRef<unsigned>(idxs, n)), name));
+}
+
+LLVMValueRef LLVM_Hs_BuildExtractElement(LLVMBuilderRef B, LLVMValueRef VecVal,
+                                         LLVMValueRef Index, const char *Name) {
+    return wrap(unwrap(B)->Insert(ExtractElementInst::Create(unwrap(VecVal), unwrap(Index)),
+                                  Name));
+}
+
+LLVMValueRef LLVM_Hs_BuildInsertElement(LLVMBuilderRef B, LLVMValueRef VecVal,
+                                        LLVMValueRef EltVal, LLVMValueRef Index,
+                                        const char *Name) {
+    return wrap(unwrap(B)->Insert(InsertElementInst::Create(unwrap(VecVal), unwrap(EltVal),
+                                                            unwrap(Index)),
+                                  Name));
+}
+
+LLVMValueRef LLVM_Hs_BuildShuffleVector(LLVMBuilderRef B, LLVMValueRef V1,
+                                        LLVMValueRef V2, int *MaskArgs,
+                                        unsigned MaskSize, const char *Name) {
+    ArrayRef<int> maskArray(MaskArgs, MaskSize);
+    return wrap(unwrap(B)->Insert(new ShuffleVectorInst(unwrap(V1), unwrap(V2),
+                                                        maskArray),
+                                  Name));
+}
+}
diff --git a/src/LLVM/Internal/FFI/ByteRangeCallback.hs b/src/LLVM/Internal/FFI/ByteRangeCallback.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ByteRangeCallback.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.ByteRangeCallback where
+
+import LLVM.Prelude
+
+import Foreign.C
+import Foreign.Ptr
+
+type ByteRangeCallback = Ptr CChar -> CSize -> IO ()
+foreign import ccall "wrapper" wrapByteRangeCallback :: 
+  ByteRangeCallback -> IO (FunPtr ByteRangeCallback)
+
diff --git a/src/LLVM/Internal/FFI/CallingConvention.h b/src/LLVM/Internal/FFI/CallingConvention.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/CallingConvention.h
@@ -0,0 +1,52 @@
+#ifndef __LLVM_INTERNAL_FFI__CALLING_CONVENTION__H__
+#define __LLVM_INTERNAL_FFI__CALLING_CONVENTION__H__
+
+#define LLVM_HS_FOR_EACH_CALLING_CONVENTION(macro) \
+  macro(C, 0)                                      \
+  macro(Fast, 8)                                   \
+  macro(Cold, 9)                                   \
+  macro(GHC, 10)                                   \
+  macro(HiPE, 11)                                  \
+  macro(WebKit_JS, 12)                             \
+  macro(AnyReg, 13)                                \
+  macro(PreserveMost, 14)                          \
+  macro(PreserveAll, 15)                           \
+  macro(Swift, 16)                                 \
+  macro(CXX_FAST_TLS, 17)                          \
+  macro(X86_StdCall, 64)                           \
+  macro(X86_FastCall, 65)                          \
+  macro(ARM_APCS, 66)                              \
+  macro(ARM_AAPCS, 67)                             \
+  macro(ARM_AAPCS_VFP, 68)                         \
+  macro(MSP430_INTR, 69)                           \
+  macro(X86_ThisCall, 70)                          \
+  macro(PTX_Kernel, 71)                            \
+  macro(PTX_Device, 72)                            \
+  macro(SPIR_FUNC, 75)                             \
+  macro(SPIR_KERNEL, 76)                           \
+  macro(Intel_OCL_BI, 77)                          \
+  macro(X86_64_SysV, 78)                           \
+  macro(Win64, 79)                                 \
+  macro(X86_VectorCall, 80)                        \
+  macro(HHVM, 81)                                  \
+  macro(HHVM_C, 82)                                \
+  macro(X86_INTR, 83)                              \
+  macro(AVR_INTR, 84)                              \
+  macro(AVR_SIGNAL, 85)                            \
+  macro(AVR_BUILTIN, 86)                           \
+  macro(AMDGPU_VS, 87)                             \
+  macro(AMDGPU_GS, 88)                             \
+  macro(AMDGPU_PS, 89)                             \
+  macro(AMDGPU_CS, 90)                             \
+  macro(AMDGPU_KERNEL, 91)                         \
+  macro(X86_RegCall, 92)                           \
+  macro(AMDGPU_HS, 93)                             \
+  macro(MSP430_BUILTIN, 94)
+
+typedef enum {
+#define ENUM_CASE(l,n) LLVM_Hs_CallingConvention_ ## l = n,
+  LLVM_HS_FOR_EACH_CALLING_CONVENTION(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_CallingConvention;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/CallingConventionC.cpp b/src/LLVM/Internal/FFI/CallingConventionC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/CallingConventionC.cpp
@@ -0,0 +1,10 @@
+#include "LLVM/Internal/FFI/CallingConvention.h"
+#include "llvm/IR/CallingConv.h"
+
+#define CHECK(l, n)                                                            \
+    static_assert(unsigned(llvm::CallingConv::l) ==                            \
+                      unsigned(LLVM_Hs_CallingConvention_##l),            \
+                  "LLVM_Hs_CallingConvention enum out of sync w/ "        \
+                  "llvm::CallingConv::ID for " #l);
+LLVM_HS_FOR_EACH_CALLING_CONVENTION(CHECK)
+#undef CHECK
diff --git a/src/LLVM/Internal/FFI/Cleanup.hs b/src/LLVM/Internal/FFI/Cleanup.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Cleanup.hs
@@ -0,0 +1,85 @@
+{-# LANGUAGE
+  TemplateHaskell
+  #-}
+module LLVM.Internal.FFI.Cleanup where
+
+import LLVM.Prelude
+
+import Language.Haskell.TH
+import Data.Sequence as Seq
+
+import Foreign.C
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.LLVMCTypes
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+
+import qualified LLVM.AST.IntegerPredicate as A (IntegerPredicate) 
+import qualified LLVM.AST.FloatingPointPredicate as A (FloatingPointPredicate) 
+import qualified LLVM.AST.Constant as A.C (Constant)
+import qualified LLVM.AST.Operand as A (Operand)
+import qualified LLVM.AST.Type as A (Type)
+import qualified LLVM.AST.Instruction as A (FastMathFlags)
+
+foreignDecl :: String -> String -> [TypeQ] -> TypeQ -> DecsQ
+foreignDecl cName hName argTypeQs returnTypeQ = do
+  let retTyQ = appT (conT ''IO) returnTypeQ
+      foreignDecl' hName argTypeQs =
+        forImpD cCall unsafe cName (mkName hName) 
+                  (foldr (\a b -> appT (appT arrowT a) b) retTyQ argTypeQs)
+      splitTuples :: [Type] -> Q ([Type], [Pat], [Exp])
+      splitTuples ts = do
+        let f :: Type -> Q (Seq Type, Pat, Seq Exp)
+            f x@(AppT _ _) = maybe (d x) (\q -> q >>= \(ts, ps, es) -> return (ts, TupP (toList ps), es)) (g 0 x)
+            f x = d x
+            g :: Int -> Type -> Maybe (Q (Seq Type, Seq Pat, Seq Exp))
+            g n (TupleT m) | m == n = return (return (Seq.empty, Seq.empty, Seq.empty))
+            g n (AppT a b) = do
+              k <- g (n+1) a
+              return $ do
+                (ts, ps, es) <- k
+                (ts', p', es') <- f b
+                return (ts >< ts', ps |> p', es >< es')
+            g _ _ = Nothing
+            d :: Type -> Q (Seq Type, Pat, Seq Exp)
+            d x = do
+              n <- newName "v"
+              return (Seq.singleton x, VarP n, Seq.singleton (VarE n))
+            seqsToList :: [Seq a] -> [a]
+            seqsToList = toList . foldr (><) Seq.empty
+                
+        (tss, ps, ess) <- liftM unzip3 . mapM f $ ts
+        return (seqsToList tss, ps, seqsToList ess)
+
+                                
+  argTypes <- sequence argTypeQs
+  (ts, ps, es) <- splitTuples argTypes
+  let phName = hName ++ "'"
+  sequence [
+    foreignDecl' phName (map return ts),
+    sigD (mkName hName) (foldr (\argT retT -> appT (appT arrowT argT) retT) retTyQ argTypeQs),
+    funD (mkName hName) [
+     clause (map return ps) (normalB (foldl appE (varE (mkName phName)) (map return es))) []
+    ]
+   ]
+
+-- | The LLVM C-API for instructions with boolean flags (e.g. nsw) and is weak, so they get
+-- separated out for different handling. This check is an accurate but crude test for whether
+-- an instruction needs such handling.
+hasFlags :: [Type] -> Bool
+hasFlags = any (== ConT ''Bool)
+
+typeMapping :: Type -> TypeQ
+typeMapping t = case t of
+  ConT h | h == ''Bool -> [t| LLVMBool |]
+         | h == ''Int32 -> [t| CInt |]
+         | h == ''Word32 -> [t| CUInt |]
+         | h == ''String -> [t| CString |]
+         | h == ''A.Operand -> [t| Ptr FFI.Value |]
+         | h == ''A.Type -> [t| Ptr FFI.Type |]
+         | h == ''A.C.Constant -> [t| Ptr FFI.Constant |]
+         | h == ''A.FloatingPointPredicate -> [t| FCmpPredicate |]
+         | h == ''A.IntegerPredicate -> [t| ICmpPredicate |]
+         | h == ''A.FastMathFlags -> [t| FastMathFlags |]
+  AppT ListT x -> foldl1 appT [tupleT 2, [t| CUInt |], appT [t| Ptr |] (typeMapping x)]
+  x -> error $ "type not handled in Cleanup typeMapping: " ++ show x
diff --git a/src/LLVM/Internal/FFI/CommandLine.hs b/src/LLVM/Internal/FFI/CommandLine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/CommandLine.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.CommandLine where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+foreign import ccall unsafe "LLVM_Hs_ParseCommandLineOptions" parseCommandLineOptions' ::
+  CUInt -> Ptr (Ptr CChar) -> Ptr CChar -> IO ()
+
+parseCommandLineOptions :: (CUInt, Ptr (Ptr CChar)) -> Ptr CChar -> IO ()
+parseCommandLineOptions = uncurry parseCommandLineOptions'
diff --git a/src/LLVM/Internal/FFI/CommandLineC.cpp b/src/LLVM/Internal/FFI/CommandLineC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/CommandLineC.cpp
@@ -0,0 +1,12 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+extern "C" {
+
+void LLVM_Hs_ParseCommandLineOptions(unsigned argc, const char * const *argv, const char *overview) {
+	cl::ParseCommandLineOptions(argc, argv, overview);
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/Constant.h b/src/LLVM/Internal/FFI/Constant.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Constant.h
@@ -0,0 +1,20 @@
+#ifndef __LLVM_INTERNAL_FFI__CONSTANT__H__
+#define __LLVM_INTERNAL_FFI__CONSTANT__H__
+
+#define LLVM_HS_FOR_EACH_FLOAT_SEMANTICS(macro) \
+    macro(IEEEhalf) \
+    macro(IEEEsingle) \
+    macro(IEEEdouble) \
+    macro(IEEEquad) \
+    macro(PPCDoubleDouble) \
+    macro(x87DoubleExtended) \
+    macro(Bogus)
+
+typedef enum {
+#define ENUM_CASE(x) LLVMFloatSemantics ## x,
+LLVM_HS_FOR_EACH_FLOAT_SEMANTICS(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMFloatSemantics;
+
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Constant.hs b/src/LLVM/Internal/FFI/Constant.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Constant.hs
@@ -0,0 +1,149 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances,
+  ViewPatterns
+  #-}
+-- | FFI functions for handling the LLVM Constant class
+module LLVM.Internal.FFI.Constant where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+import qualified LLVM.Internal.InstructionDefs as ID
+
+import qualified Data.Map as Map
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.Cleanup
+import LLVM.Internal.FFI.LLVMCTypes
+
+foreign import ccall unsafe "LLVMIsConstant" isConstant ::
+  Ptr Value -> IO (CUInt)
+
+foreign import ccall unsafe "LLVMIsAConstant" isAConstant ::
+  Ptr Value -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMIsAConstantInt" isAConstantInt ::
+  Ptr Value -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMGetOperand" getConstantOperand ::
+  Ptr Constant -> CUInt -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMIsAConstantPointerNull" isAConstantPointerNull ::
+  Ptr Value -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_GetConstantIntWords" getConstantIntWords ::
+  Ptr Constant -> Ptr CUInt -> IO (Ptr Word64)
+
+foreign import ccall unsafe "LLVM_Hs_ConstFloatDoubleValue" constFloatDoubleValue ::
+  Ptr Constant -> IO CDouble
+
+foreign import ccall unsafe "LLVM_Hs_ConstFloatFloatValue" constFloatFloatValue ::
+  Ptr Constant -> IO CFloat
+
+foreign import ccall unsafe "LLVMConstStructInContext" constStructInContext' ::
+  Ptr Context -> Ptr (Ptr Constant) -> CUInt -> LLVMBool -> IO (Ptr Constant)
+
+constStructInContext :: Ptr Context -> (CUInt, Ptr (Ptr Constant)) -> LLVMBool -> IO (Ptr Constant)
+constStructInContext ctx (n, cs) p = constStructInContext' ctx cs n p
+
+foreign import ccall unsafe "LLVMConstNamedStruct" constNamedStruct' ::
+  Ptr Type -> Ptr (Ptr Constant) -> CUInt -> IO (Ptr Constant)
+
+constNamedStruct :: Ptr Type -> (CUInt, Ptr (Ptr Constant)) -> IO (Ptr Constant)
+constNamedStruct ty (n, cs) = constNamedStruct' ty cs n
+
+foreign import ccall unsafe "LLVM_Hs_GetConstantDataSequentialElementAsConstant" getConstantDataSequentialElementAsConstant ::
+  Ptr Constant -> CUInt -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMConstIntOfArbitraryPrecision" constantIntOfArbitraryPrecision' ::
+  Ptr Type -> CUInt -> Ptr Word64 -> IO (Ptr Constant)
+
+constantIntOfArbitraryPrecision :: Ptr Type -> (CUInt, Ptr Word64) -> IO (Ptr Constant)
+constantIntOfArbitraryPrecision t = uncurry (constantIntOfArbitraryPrecision' t)
+
+foreign import ccall unsafe "LLVM_Hs_ConstFloatOfArbitraryPrecision" constantFloatOfArbitraryPrecision ::
+  Ptr Context -> CUInt -> Ptr Word64 -> FloatSemantics -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_GetConstantFloatWords" getConstantFloatWords ::
+  Ptr Constant -> Ptr Word64 -> IO ()
+
+foreign import ccall unsafe "LLVMConstVector" constantVector' ::
+  Ptr (Ptr Constant) -> CUInt -> IO (Ptr Constant)
+
+constantVector :: (CUInt, Ptr (Ptr Constant)) -> IO (Ptr Constant)
+constantVector (n, cs) = constantVector' cs n
+
+foreign import ccall unsafe "LLVMConstNull" constantNull ::
+  Ptr Type -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMConstArray" constantArray' ::
+  Ptr Type -> Ptr (Ptr Constant) -> CUInt -> IO (Ptr Constant)
+
+constantArray :: Ptr Type -> (CUInt, Ptr (Ptr Constant)) -> IO (Ptr Constant)
+constantArray t (n, cs) = constantArray' t cs n
+
+foreign import ccall unsafe "LLVM_Hs_ConstCast" constantCast ::
+  CPPOpcode -> Ptr Constant -> Ptr Type -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_ConstBinaryOperator" constantBinaryOperator ::
+  CPPOpcode -> Ptr Constant -> Ptr Constant -> IO (Ptr Constant)
+
+$(do
+   let constExprInfo = ID.innerJoin (ID.innerJoin ID.astConstantRecs ID.astInstructionRecs) ID.instructionDefs
+   liftM concat $ sequence $ do
+     (name, ((TH.RecC _ (unzip3 -> (_, _, fieldTypes)),_), ID.InstructionDef { ID.instructionKind = ik })) <- Map.toList constExprInfo
+     prefix <- case ik of
+                 ID.Other -> return "LLVM"
+                 ID.Binary | hasFlags fieldTypes -> return "LLVM_Hs_"
+                 _ -> []
+     return $
+       foreignDecl (prefix ++ "Const" ++ name) ("constant" ++ name) (map typeMapping fieldTypes) [t| Ptr Constant |]
+  )
+
+foreign import ccall unsafe "LLVMConstGEP" constantGetElementPtr' ::
+  Ptr Constant -> Ptr (Ptr Constant) -> CUInt -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMConstInBoundsGEP" constantInBoundsGetElementPtr' ::
+  Ptr Constant -> Ptr (Ptr Constant) -> CUInt -> IO (Ptr Constant)
+
+constantGetElementPtr :: LLVMBool -> Ptr Constant -> (CUInt, Ptr (Ptr Constant)) -> IO (Ptr Constant)
+constantGetElementPtr (LLVMBool ib) a (n, is) =
+  (case ib of
+     0 -> constantGetElementPtr'
+     1 -> constantInBoundsGetElementPtr'
+     _ -> error ("LLVMBool should be 0 or 1 but is " <> show ib)
+  ) a is n
+
+foreign import ccall unsafe "LLVM_Hs_GetConstCPPOpcode" getConstantCPPOpcode ::
+  Ptr Constant -> IO CPPOpcode
+
+foreign import ccall unsafe "LLVM_Hs_GetConstPredicate" getConstantICmpPredicate ::
+  Ptr Constant -> IO ICmpPredicate
+
+foreign import ccall unsafe "LLVM_Hs_GetConstPredicate" getConstantFCmpPredicate ::
+  Ptr Constant -> IO FCmpPredicate
+
+foreign import ccall unsafe "LLVM_Hs_GetConstIndices" getConstantIndices ::
+  Ptr Constant -> Ptr CUInt -> IO (Ptr CUInt)
+
+foreign import ccall unsafe "LLVMGetUndef" constantUndef ::
+  Ptr Type -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMBlockAddress" blockAddress ::
+  Ptr Value -> Ptr BasicBlock -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_GetBlockAddressFunction" getBlockAddressFunction ::
+  Ptr Constant -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_GetBlockAddressBlock" getBlockAddressBlock ::
+  Ptr Constant -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVM_Hs_GetConstTokenNone" getConstTokenNone ::
+  Ptr Context -> IO (Ptr Constant)
diff --git a/src/LLVM/Internal/FFI/ConstantC.cpp b/src/LLVM/Internal/FFI/ConstantC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ConstantC.cpp
@@ -0,0 +1,131 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+
+#include "llvm-c/Core.h"
+#include "LLVM/Internal/FFI/Value.h"
+#include "LLVM/Internal/FFI/Constant.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+static const struct fltSemantics &unwrap(LLVMFloatSemantics s) {
+    switch(s) {
+#define ENUM_CASE(x) case LLVMFloatSemantics ## x: return APFloat::x();
+LLVM_HS_FOR_EACH_FLOAT_SEMANTICS(ENUM_CASE)
+#undef ENUM_CASE
+    default: return APFloat::Bogus();
+    }
+}
+
+}
+
+extern "C" {
+
+LLVMValueRef LLVM_Hs_GetConstantDataSequentialElementAsConstant(LLVMValueRef v, unsigned i) {
+    return wrap(unwrap<ConstantDataSequential>(v)->getElementAsConstant(i));
+}
+
+LLVMValueRef LLVM_Hs_GetBlockAddressFunction(LLVMValueRef v) {
+    return wrap(unwrap<BlockAddress>(v)->getFunction());
+}
+
+LLVMBasicBlockRef LLVM_Hs_GetBlockAddressBlock(LLVMValueRef v) {
+    return wrap(unwrap<BlockAddress>(v)->getBasicBlock());
+}
+
+double LLVM_Hs_ConstFloatDoubleValue(LLVMValueRef v) {
+    return unwrap<ConstantFP>(v)->getValueAPF().convertToDouble();
+}
+
+float LLVM_Hs_ConstFloatFloatValue(LLVMValueRef v) {
+    return unwrap<ConstantFP>(v)->getValueAPF().convertToFloat();
+}
+
+LLVMValueRef LLVM_Hs_ConstCast(unsigned opcode, LLVMValueRef v, LLVMTypeRef t) {
+    return wrap(ConstantExpr::getCast(opcode, unwrap<Constant>(v), unwrap(t)));
+}
+
+LLVMValueRef LLVM_Hs_ConstBinaryOperator(unsigned opcode, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::get(opcode, unwrap<Constant>(o0), unwrap<Constant>(o1)));
+}
+
+LLVMValueRef LLVM_Hs_ConstAdd(unsigned nsw, unsigned nuw, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getAdd(unwrap<Constant>(o0), unwrap<Constant>(o1), nuw != 0, nsw != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstMul(unsigned nsw, unsigned nuw, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getMul(unwrap<Constant>(o0), unwrap<Constant>(o1), nuw != 0, nsw != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstShl(unsigned nsw, unsigned nuw, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getShl(unwrap<Constant>(o0), unwrap<Constant>(o1), nuw != 0, nsw != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstSub(unsigned nsw, unsigned nuw, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getSub(unwrap<Constant>(o0), unwrap<Constant>(o1), nuw != 0, nsw != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstUDiv(unsigned isExact, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getUDiv(unwrap<Constant>(o0), unwrap<Constant>(o1), isExact != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstSDiv(unsigned isExact, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getSDiv(unwrap<Constant>(o0), unwrap<Constant>(o1), isExact != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstLShr(unsigned isExact, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getLShr(unwrap<Constant>(o0), unwrap<Constant>(o1), isExact != 0));
+}
+
+LLVMValueRef LLVM_Hs_ConstAShr(unsigned isExact, LLVMValueRef o0, LLVMValueRef o1) {
+    return wrap(ConstantExpr::getAShr(unwrap<Constant>(o0), unwrap<Constant>(o1), isExact != 0));
+}
+
+unsigned LLVM_Hs_GetConstCPPOpcode(LLVMValueRef v) {
+    return unwrap<ConstantExpr>(v)->getOpcode();
+}
+
+unsigned LLVM_Hs_GetConstPredicate(LLVMValueRef v) {
+    return unwrap<ConstantExpr>(v)->getPredicate();
+}
+
+const unsigned *LLVM_Hs_GetConstIndices(LLVMValueRef v, unsigned *n) {
+    ArrayRef<unsigned> r = unwrap<ConstantExpr>(v)->getIndices();
+    *n = r.size();
+    return r.data();
+}
+
+const uint64_t *LLVM_Hs_GetConstantIntWords(LLVMValueRef v, unsigned *n) {
+    const APInt &i = unwrap<ConstantInt>(v)->getValue();
+    *n = i.getNumWords();
+    return i.getRawData();
+}
+
+LLVMValueRef LLVM_Hs_ConstFloatOfArbitraryPrecision(
+    LLVMContextRef c,
+    unsigned bits,
+    const uint64_t *words,
+    LLVMFloatSemantics semantics
+) {
+    return wrap(
+        ConstantFP::get(
+            *unwrap(c),
+            APFloat(unwrap(semantics), APInt(bits, ArrayRef<uint64_t>(words, (bits-1)/64 + 1)))
+        )
+    );
+}
+
+void LLVM_Hs_GetConstantFloatWords(LLVMValueRef v, uint64_t *bits) {
+    APInt a = unwrap<ConstantFP>(v)->getValueAPF().bitcastToAPInt();
+    for(unsigned i=0; i != a.getNumWords(); ++i) bits[i] = a.getRawData()[i];
+}
+
+LLVMValueRef LLVM_Hs_GetConstTokenNone(LLVMContextRef context) {
+    return wrap(ConstantTokenNone::get(*unwrap(context)));
+}
+
+
+}
diff --git a/src/LLVM/Internal/FFI/Context.hs b/src/LLVM/Internal/FFI/Context.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Context.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+-- | Functions for handling the LLVMContext class. In all other LLVM interfaces,
+-- | prefer the newer explicitly thread-aware variants which use contexts
+-- | over corresponding older variants which implicitly reference a global context.
+-- | This choice allows multiple threads to do independent work with LLVM safely.
+module LLVM.Internal.FFI.Context where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+
+-- | a blind type to correspond to LLVMContext
+data Context
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreContext.html#gaac4f39a2d0b9735e64ac7681ab543b4c>
+foreign import ccall unsafe "LLVMContextCreate" contextCreate ::
+    IO (Ptr Context)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreContext.html#ga0055cde9a9b2497b332d639d8844a810>
+foreign import ccall unsafe "LLVMGetGlobalContext" getGlobalContext ::
+    IO (Ptr Context)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreContext.html#ga9cf8b0fb4a546d4cdb6f64b8055f5f57>
+foreign import ccall unsafe "LLVMContextDispose" contextDispose ::
+    Ptr Context -> IO ()
diff --git a/src/LLVM/Internal/FFI/DataLayout.hs b/src/LLVM/Internal/FFI/DataLayout.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/DataLayout.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+module LLVM.Internal.FFI.DataLayout where
+
+import LLVM.Prelude
+
+import Foreign.C
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+data DataLayout
+
+-- Oooh those wacky LLVM C-API coders: C API called DataLayout TargetData.
+-- Great. Just great.
+
+foreign import ccall unsafe "LLVMCreateTargetData" createDataLayout :: 
+  CString -> IO (Ptr DataLayout)
+
+foreign import ccall unsafe "LLVMDisposeTargetData" disposeDataLayout :: 
+  Ptr DataLayout -> IO ()
+
+foreign import ccall unsafe "LLVMCopyStringRepOfTargetData" dataLayoutToString ::
+  Ptr DataLayout -> IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVMABISizeOfType" getTypeAllocSize ::
+  Ptr DataLayout -> Ptr Type -> IO Word64
+
+foreign import ccall unsafe "LLVMOffsetOfElement" getOffsetOfElement ::
+  Ptr DataLayout -> Ptr Type -> CUInt -> IO Word64
diff --git a/src/LLVM/Internal/FFI/DynamicLibrary.hs b/src/LLVM/Internal/FFI/DynamicLibrary.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/DynamicLibrary.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- | FFI functions for handling the DynamicLibrary class
+module LLVM.Internal.FFI.DynamicLibrary where
+
+import LLVM.Prelude
+
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+-- | <https://llvm.org/doxygen/Support_8h.html#a6fc1331c1a6d2cc6f0fda94f4a4636f9>
+foreign import ccall safe "LLVMLoadLibraryPermanently" loadLibraryPermanently ::
+  CString -> IO LLVMBool
diff --git a/src/LLVM/Internal/FFI/ErrorHandling.cpp b/src/LLVM/Internal/FFI/ErrorHandling.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ErrorHandling.cpp
@@ -0,0 +1,9 @@
+#include "LLVM/Internal/FFI/ErrorHandling.hpp"
+#include <iostream>
+#include <cstdlib>
+
+void reportFatalError(const std::string &errorMsg) {
+    std::cerr << "LLVM-HS ERROR at " << __FILE__ << ":" << __LINE__ << ": "
+              << errorMsg << "\n ";
+    exit(1);
+}
diff --git a/src/LLVM/Internal/FFI/ErrorHandling.hpp b/src/LLVM/Internal/FFI/ErrorHandling.hpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ErrorHandling.hpp
@@ -0,0 +1,7 @@
+#ifndef __LLVM_INTERNAL_FFI__ERRORHANDLING__H__
+#define __LLVM_INTERNAL_FFI__ERRORHANDLING__H__
+#include <string>
+
+[[noreturn]] void reportFatalError(const std::string &errorMsg);
+
+#endif
diff --git a/src/LLVM/Internal/FFI/ExecutionEngine.hs b/src/LLVM/Internal/FFI/ExecutionEngine.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ExecutionEngine.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+module LLVM.Internal.FFI.ExecutionEngine where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.Module
+import LLVM.Internal.FFI.LLVMCTypes
+
+data ExecutionEngine
+
+foreign import ccall unsafe "LLVMCreateExecutionEngineForModule" createExecutionEngineForModule ::
+  Ptr (Ptr ExecutionEngine) -> Ptr Module -> Ptr (OwnerTransfered CString) -> IO CUInt
+
+foreign import ccall unsafe "LLVMCreateInterpreterForModule" createInterpreterForModule ::
+  Ptr (Ptr ExecutionEngine) -> Ptr Module -> Ptr (OwnerTransfered CString) -> IO CUInt
+
+foreign import ccall unsafe "LLVMCreateJITCompilerForModule" createJITCompilerForModule ::
+  Ptr (Ptr ExecutionEngine) -> Ptr Module -> CUInt -> Ptr (OwnerTransfered CString) -> IO CUInt
+
+foreign import ccall unsafe "LLVMCreateMCJITCompilerForModule" createMCJITCompilerForModule ::
+  Ptr (Ptr ExecutionEngine) -> Ptr Module -> Ptr MCJITCompilerOptions -> CSize -> Ptr (OwnerTransfered CString) -> IO CUInt
+
+foreign import ccall unsafe "LLVMDisposeExecutionEngine" disposeExecutionEngine ::
+  Ptr ExecutionEngine -> IO ()
+
+foreign import ccall unsafe "LLVMAddModule" addModule ::
+  Ptr ExecutionEngine -> Ptr Module -> IO ()
+
+foreign import ccall unsafe "LLVMRemoveModule" removeModule ::
+  Ptr ExecutionEngine -> Ptr Module -> Ptr (Ptr Module) -> Ptr CString -> IO CUInt
+
+foreign import ccall unsafe "LLVMFindFunction" findFunction ::
+  Ptr ExecutionEngine -> CString -> Ptr (Ptr Function) -> IO CUInt
+
+foreign import ccall unsafe "LLVMGetPointerToGlobal" getPointerToGlobal ::
+  Ptr ExecutionEngine -> Ptr GlobalValue -> IO (Ptr ())
+
+foreign import ccall unsafe "LLVMLinkInInterpreter" linkInInterpreter :: 
+  IO ()
+
+foreign import ccall unsafe "LLVMLinkInMCJIT" linkInMCJIT :: 
+  IO ()
+
+data MCJITCompilerOptions
+
+foreign import ccall unsafe "LLVM_Hs_GetMCJITCompilerOptionsSize" getMCJITCompilerOptionsSize ::
+  IO CSize
+
+foreign import ccall unsafe "LLVMInitializeMCJITCompilerOptions" initializeMCJITCompilerOptions ::
+  Ptr MCJITCompilerOptions -> CSize -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetMCJITCompilerOptionsOptLevel" setMCJITCompilerOptionsOptLevel ::
+  Ptr MCJITCompilerOptions -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetMCJITCompilerOptionsCodeModel" setMCJITCompilerOptionsCodeModel ::
+  Ptr MCJITCompilerOptions -> CodeModel -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetMCJITCompilerOptionsNoFramePointerElim" setMCJITCompilerOptionsNoFramePointerElim ::
+  Ptr MCJITCompilerOptions -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetMCJITCompilerOptionsEnableFastISel" setMCJITCompilerOptionsEnableFastISel ::
+  Ptr MCJITCompilerOptions -> LLVMBool -> IO ()
+
+
diff --git a/src/LLVM/Internal/FFI/ExecutionEngineC.cpp b/src/LLVM/Internal/FFI/ExecutionEngineC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ExecutionEngineC.cpp
@@ -0,0 +1,30 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm-c/ExecutionEngine.h"
+
+using namespace llvm;
+
+extern "C" {
+
+size_t LLVM_Hs_GetMCJITCompilerOptionsSize() {
+  return sizeof(struct LLVMMCJITCompilerOptions);
+}
+
+void LLVM_Hs_SetMCJITCompilerOptionsOptLevel(struct LLVMMCJITCompilerOptions *o, unsigned x) {
+  o->OptLevel = x;
+}
+
+void LLVM_Hs_SetMCJITCompilerOptionsCodeModel(struct LLVMMCJITCompilerOptions *o, LLVMCodeModel x) {
+  o->CodeModel = x;
+}
+
+void LLVM_Hs_SetMCJITCompilerOptionsNoFramePointerElim(struct LLVMMCJITCompilerOptions *o, LLVMBool x) {
+  o->NoFramePointerElim = x;
+}
+
+void LLVM_Hs_SetMCJITCompilerOptionsEnableFastISel(struct LLVMMCJITCompilerOptions *o, LLVMBool x) {
+  o->EnableFastISel = x;
+}
+
+}
+
diff --git a/src/LLVM/Internal/FFI/Function.hs b/src/LLVM/Internal/FFI/Function.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Function.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses
+  #-}
+
+module LLVM.Internal.FFI.Function where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.Attribute
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+foreign import ccall unsafe "LLVMGetFunctionCallConv" getFunctionCallingConvention ::
+  Ptr Function -> IO CallingConvention
+
+foreign import ccall unsafe "LLVMSetFunctionCallConv" setFunctionCallingConvention ::
+  Ptr Function -> CallingConvention -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetFunctionAttributeList" setAttributeList ::
+  Ptr Function -> AttributeList -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_FunctionAttributesAtIndex" attributesAtIndex ::
+  Ptr Function -> AttributeIndex -> IO (AttributeSet b)
+
+foreign import ccall unsafe "LLVMGetFirstBasicBlock" getFirstBasicBlock ::
+  Ptr Function -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVMGetLastBasicBlock" getLastBasicBlock ::
+  Ptr Function -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVMGetNextBasicBlock" getNextBasicBlock ::
+  Ptr BasicBlock -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVMAppendBasicBlockInContext" appendBasicBlockInContext ::
+  Ptr Context -> Ptr Function -> CString -> IO (Ptr BasicBlock)
+
+
+foreign import ccall unsafe "LLVMCountParams" countParams ::
+  Ptr Function -> IO CUInt
+
+foreign import ccall unsafe "LLVMGetParams" getParams ::
+  Ptr Function -> Ptr (Ptr Parameter) -> IO ()
+
+foreign import ccall unsafe "LLVMGetGC" getGC ::
+  Ptr Function -> IO CString
+
+foreign import ccall unsafe "LLVMSetGC" setGC ::
+  Ptr Function -> CString -> IO ()
+
+
+foreign import ccall unsafe "LLVM_Hs_HasFunctionPrefixData" hasPrefixData ::
+  Ptr Function -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetFunctionPrefixData" getPrefixData ::
+  Ptr Function -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_SetFunctionPrefixData" setPrefixData ::
+  Ptr Function -> Ptr Constant -> IO ()
+
+foreign import ccall unsafe "LLVMHasPersonalityFn" hasPersonalityFn ::
+  Ptr Function -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_SetPersonalityFn" setPersonalityFn ::
+  Ptr Function -> Ptr Constant -> IO ()
+
+foreign import ccall unsafe "LLVMGetPersonalityFn" getPersonalityFn ::
+  Ptr Function -> IO (Ptr Constant)
diff --git a/src/LLVM/Internal/FFI/FunctionC.cpp b/src/LLVM/Internal/FFI/FunctionC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/FunctionC.cpp
@@ -0,0 +1,42 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Value.h"
+
+#include "LLVM/Internal/FFI/AttributeC.hpp"
+#include "llvm-c/Core.h"
+
+using namespace llvm;
+
+extern "C" {
+void LLVM_Hs_SetFunctionAttributeList(LLVMValueRef f,
+                                      LLVMAttributeListRef attrs) {
+    unwrap<Function>(f)->setAttributes(*attrs);
+}
+
+LLVMBool LLVM_Hs_HasFunctionPrefixData(LLVMValueRef f) {
+    return unwrap<Function>(f)->hasPrefixData();
+}
+
+LLVMValueRef LLVM_Hs_GetFunctionPrefixData(LLVMValueRef f) {
+    return wrap(unwrap<Function>(f)->getPrefixData());
+}
+
+void LLVM_Hs_SetFunctionPrefixData(LLVMValueRef f, LLVMValueRef p) {
+    unwrap<Function>(f)->setPrefixData(unwrap<Constant>(p));
+}
+
+// This wrapper is necessary because LLVMSetPersonalityFn fails if
+// personalityFn is a nullptr even though the C++ API allows that.
+void LLVM_Hs_SetPersonalityFn(LLVMValueRef fn, LLVMValueRef personalityFn) {
+    unwrap<Function>(fn)->setPersonalityFn(
+        personalityFn == nullptr ? nullptr : unwrap<Constant>(personalityFn));
+}
+
+LLVMAttributeSetRef LLVM_Hs_FunctionAttributesAtIndex(LLVMValueRef fn,
+                                                      LLVMAttributeIndex idx) {
+    return new AttributeSet(
+        unwrap<Function>(fn)->getAttributes().getAttributes(idx));
+}
+}
diff --git a/src/LLVM/Internal/FFI/GlobalAlias.hs b/src/LLVM/Internal/FFI/GlobalAlias.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalAlias.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM GlobalAlias class
+module LLVM.Internal.FFI.GlobalAlias where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.PtrHierarchy
+
+-- | test if a 'Value' is a 'GlobalAlias'
+foreign import ccall unsafe "LLVMIsAGlobalAlias" isAGlobalAlias ::
+    Ptr Value -> IO (Ptr GlobalAlias)
+
+-- | get the constant aliased by this alias
+foreign import ccall unsafe "LLVM_Hs_GetAliasee" getAliasee ::
+    Ptr GlobalAlias -> IO (Ptr Constant)
+
+-- | set the constant aliased by this alias
+foreign import ccall unsafe "LLVM_Hs_SetAliasee" setAliasee ::
+    Ptr GlobalAlias -> Ptr Constant -> IO ()
+
diff --git a/src/LLVM/Internal/FFI/GlobalAliasC.cpp b/src/LLVM/Internal/FFI/GlobalAliasC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalAliasC.cpp
@@ -0,0 +1,22 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalObject.h"
+
+#include "llvm-c/Core.h"
+
+#include <iostream>
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMValueRef LLVM_Hs_GetAliasee(LLVMValueRef g) {
+	return wrap(unwrap<GlobalAlias>(g)->getAliasee());
+}
+
+void LLVM_Hs_SetAliasee(LLVMValueRef g, LLVMValueRef c) {
+	unwrap<GlobalAlias>(g)->setAliasee(unwrap<Constant>(c));
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/GlobalValue.h b/src/LLVM/Internal/FFI/GlobalValue.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalValue.h
@@ -0,0 +1,51 @@
+#ifndef __LLVM_INTERNAL_FFI__GLOBAL_VALUE__H__
+#define __LLVM_INTERNAL_FFI__GLOBAL_VALUE__H__
+
+#define LLVM_HS_FOR_EACH_LINKAGE(macro)		\
+	macro(External)																\
+	macro(AvailableExternally)										\
+	macro(LinkOnceAny)														\
+	macro(LinkOnceODR)														\
+	macro(WeakAny)																\
+	macro(WeakODR)																\
+	macro(Appending)															\
+	macro(Internal)																\
+	macro(Private)																\
+	macro(ExternalWeak)														\
+	macro(Common)
+
+#define LLVM_HS_FOR_EACH_VISIBILITY(macro)	\
+	macro(Default)																\
+	macro(Hidden)																	\
+	macro(Protected)															\
+
+#define LLVM_HS_FOR_EACH_COMDAT_SELECTION_KIND(macro)	\
+	macro(Any)                                                \
+	macro(ExactMatch)                                         \
+	macro(Largest)                                            \
+	macro(NoDuplicates)                                       \
+	macro(SameSize)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_COMDAT_Selection_Kind_ ## n,
+LLVM_HS_FOR_EACH_COMDAT_SELECTION_KIND(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_COMDAT_Selection_Kind;
+
+#define LLVM_HS_FOR_EACH_DLL_STORAGE_CLASS(macro)	\
+	macro(Default)                                        \
+	macro(DLLImport)                                      \
+	macro(DLLExport)
+
+#define LLVM_HS_FOR_EACH_THREAD_LOCAL_MODE(macro)  \
+	macro(NotThreadLocal)                                 \
+	macro(GeneralDynamicTLSModel)                         \
+	macro(LocalDynamicTLSModel)                           \
+	macro(InitialExecTLSModel)                            \
+	macro(LocalExecTLSModel)
+
+#define LLVM_HS_FOR_EACH_UNNAMED_ADDR(macro) \
+	macro(No)                                \
+	macro(Local)                             \
+	macro(Global)
+#endif
diff --git a/src/LLVM/Internal/FFI/GlobalValue.hs b/src/LLVM/Internal/FFI/GlobalValue.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalValue.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM GlobalValue class
+module LLVM.Internal.FFI.GlobalValue where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.LLVMCTypes
+
+data COMDAT
+
+foreign import ccall unsafe "LLVMIsAGlobalValue" isAGlobalValue ::
+  Ptr Value -> IO (Ptr GlobalValue)
+
+foreign import ccall unsafe "LLVMGetLinkage" getLinkage ::
+  Ptr GlobalValue -> IO Linkage
+
+foreign import ccall unsafe "LLVMSetLinkage" setLinkage ::
+  Ptr GlobalValue -> Linkage -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetSection" getSection ::
+  Ptr GlobalValue -> Ptr CSize -> IO CString
+
+foreign import ccall unsafe "LLVMSetSection" setSection ::
+  Ptr GlobalValue -> CString -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetCOMDAT" getCOMDAT ::
+  Ptr GlobalValue -> IO (Ptr COMDAT)
+
+foreign import ccall unsafe "LLVM_Hs_SetCOMDAT" setCOMDAT ::
+  Ptr GlobalObject -> Ptr COMDAT -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetCOMDATName" getCOMDATName ::
+  Ptr COMDAT -> Ptr CSize -> IO (Ptr CChar)
+
+foreign import ccall unsafe "LLVM_Hs_GetCOMDATSelectionKind" getCOMDATSelectionKind ::
+  Ptr COMDAT -> IO COMDATSelectionKind
+
+foreign import ccall unsafe "LLVM_Hs_SetCOMDATSelectionKind" setCOMDATSelectionKind ::
+  Ptr COMDAT -> COMDATSelectionKind -> IO ()
+
+foreign import ccall unsafe "LLVMGetVisibility" getVisibility ::
+  Ptr GlobalValue -> IO Visibility
+
+foreign import ccall unsafe "LLVMSetVisibility" setVisibility ::
+  Ptr GlobalValue -> Visibility -> IO ()
+
+foreign import ccall unsafe "LLVMGetDLLStorageClass" getDLLStorageClass ::
+  Ptr GlobalValue -> IO DLLStorageClass
+
+foreign import ccall unsafe "LLVMSetDLLStorageClass" setDLLStorageClass ::
+  Ptr GlobalValue -> DLLStorageClass -> IO ()
+
+foreign import ccall unsafe "LLVMGetAlignment" getAlignment ::
+  Ptr GlobalValue -> IO CUInt
+
+foreign import ccall unsafe "LLVMSetAlignment" setAlignment ::
+  Ptr GlobalValue -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMGetUnnamedAddress" getUnnamedAddr ::
+  Ptr GlobalValue -> IO UnnamedAddr
+
+foreign import ccall unsafe "LLVMSetUnnamedAddress" setUnnamedAddr ::
+  Ptr GlobalValue -> UnnamedAddr -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetThreadLocalMode" getThreadLocalMode ::
+  Ptr GlobalValue -> IO ThreadLocalMode
+
+foreign import ccall unsafe "LLVM_Hs_SetThreadLocalMode" setThreadLocalMode ::
+  Ptr GlobalValue -> ThreadLocalMode -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GlobalObject_GetNumMetadata" getNumMetadata ::
+  Ptr GlobalObject -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GlobalObject_GetAllMetadata" getAllMetadata ::
+  Ptr GlobalObject -> Ptr MDKindID -> Ptr (Ptr MDNode) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GlobalObject_SetMetadata" setMetadata ::
+  Ptr GlobalObject -> MDKindID -> Ptr MDNode -> IO ()
diff --git a/src/LLVM/Internal/FFI/GlobalValueC.cpp b/src/LLVM/Internal/FFI/GlobalValueC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalValueC.cpp
@@ -0,0 +1,81 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/Comdat.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm-c/Core.h"
+#include "LLVM/Internal/FFI/GlobalValue.h"
+
+using namespace llvm;
+
+extern "C" {
+
+const Comdat *LLVM_Hs_GetCOMDAT(LLVMValueRef globalVal) {
+  return unwrap<GlobalValue>(globalVal)->getComdat();
+}
+
+void LLVM_Hs_SetCOMDAT(LLVMValueRef globalObj, Comdat *comdat) {
+  return unwrap<GlobalObject>(globalObj)->setComdat(comdat);
+}
+
+const char *LLVM_Hs_GetCOMDATName(const Comdat &comdat, size_t &size) {
+  StringRef ref = comdat.getName();
+  size = ref.size();
+  return ref.data();
+}
+
+#define ENUM_CASE(n)                                                           \
+    static_assert(unsigned(Comdat::n) ==                                       \
+                      unsigned(LLVM_Hs_COMDAT_Selection_Kind_##n),        \
+                  "COMDAT SelectionKind Enum mismatch");
+LLVM_HS_FOR_EACH_COMDAT_SELECTION_KIND(ENUM_CASE)
+#undef ENUM_CASE
+
+const char* LLVM_Hs_GetSection(LLVMValueRef globalVal, size_t* strLength) {
+    const auto& section = unwrap<GlobalValue>(globalVal)->getSection();
+    *strLength = section.size();
+    return section.data();
+}
+
+unsigned LLVM_Hs_GetCOMDATSelectionKind(const Comdat &comdat) {
+  return unsigned(comdat.getSelectionKind());
+}
+
+void LLVM_Hs_SetCOMDATSelectionKind(Comdat &comdat, unsigned csk) {
+  comdat.setSelectionKind(Comdat::SelectionKind(csk));
+}
+
+#define ENUM_CASE(n)                                                           \
+    static_assert(unsigned(GlobalValue::n) == unsigned(LLVM##n),               \
+                  "TLS Model Enum mismatch");
+LLVM_HS_FOR_EACH_THREAD_LOCAL_MODE(ENUM_CASE)
+#undef ENUM_CASE
+
+LLVMThreadLocalMode LLVM_Hs_GetThreadLocalMode(LLVMValueRef globalVal) {
+    return LLVMThreadLocalMode(unwrap<GlobalValue>(globalVal)->getThreadLocalMode());
+}
+
+void LLVM_Hs_SetThreadLocalMode(LLVMValueRef globalVal, LLVMThreadLocalMode mode) {
+    unwrap<GlobalValue>(globalVal)->setThreadLocalMode(GlobalValue::ThreadLocalMode(mode));
+}
+
+unsigned LLVM_Hs_GlobalObject_GetNumMetadata(GlobalObject* obj) {
+    SmallVector<std::pair<unsigned, MDNode *>, 4> mds;
+    obj->getAllMetadata(mds);
+    return mds.size();
+}
+
+void LLVM_Hs_GlobalObject_GetAllMetadata(GlobalObject* obj, unsigned *kinds, LLVMMetadataRef *nodes) {
+    SmallVector<std::pair<unsigned, MDNode*>, 4> mds;
+    obj->getAllMetadata(mds);
+    for (unsigned i = 0; i < mds.size(); ++i) {
+        kinds[i] = mds[i].first;
+        nodes[i] = wrap(mds[i].second);
+    }
+}
+
+void LLVM_Hs_GlobalObject_SetMetadata(GlobalObject* obj, unsigned kind, MDNode* node) {
+    obj->setMetadata(kind, node);
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/GlobalVariable.hs b/src/LLVM/Internal/FFI/GlobalVariable.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/GlobalVariable.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM GlobalVariable class
+module LLVM.Internal.FFI.GlobalVariable where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.LLVMCTypes
+
+foreign import ccall unsafe "LLVMIsAGlobalVariable" isAGlobalVariable ::
+    Ptr Value -> IO (Ptr GlobalVariable)
+
+foreign import ccall unsafe "LLVMIsGlobalConstant" isGlobalConstant ::
+    Ptr GlobalVariable -> IO LLVMBool
+
+foreign import ccall unsafe "LLVMSetGlobalConstant" setGlobalConstant ::
+    Ptr GlobalVariable -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVMGetInitializer" getInitializer ::
+    Ptr GlobalVariable -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVMSetInitializer" setInitializer ::
+    Ptr GlobalVariable -> Ptr Constant -> IO ()
+
diff --git a/src/LLVM/Internal/FFI/InlineAssembly.h b/src/LLVM/Internal/FFI/InlineAssembly.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/InlineAssembly.h
@@ -0,0 +1,14 @@
+#ifndef __LLVM_INTERNAL_FFI__INLINE_ASSEMBLY__H__
+#define __LLVM_INTERNAL_FFI__INLINE_ASSEMBLY__H__
+
+#define LLVM_HS_FOR_EACH_ASM_DIALECT(macro) \
+	macro(ATT) \
+	macro(Intel) \
+
+typedef enum {
+#define ENUM_CASE(d) LLVMAsmDialect_ ## d,
+	LLVM_HS_FOR_EACH_ASM_DIALECT(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMAsmDialect;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/InlineAssembly.hs b/src/LLVM/Internal/FFI/InlineAssembly.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/InlineAssembly.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+module LLVM.Internal.FFI.InlineAssembly where
+
+import LLVM.Prelude
+
+import Foreign.C
+import Foreign.Ptr
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+foreign import ccall unsafe "LLVMIsAInlineAsm" isAInlineAsm ::
+  Ptr Value -> IO (Ptr InlineAsm)
+
+foreign import ccall unsafe "LLVM_Hs_CreateInlineAsm" createInlineAsm ::
+  Ptr Type -> CString -> CString -> LLVMBool -> LLVMBool -> AsmDialect -> IO (Ptr InlineAsm)
+
+foreign import ccall unsafe "LLVM_Hs_GetInlineAsmAsmString" getInlineAsmAssemblyString ::
+  Ptr InlineAsm -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_GetInlineAsmConstraintString" getInlineAsmConstraintString ::
+  Ptr InlineAsm -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_InlineAsmHasSideEffects" inlineAsmHasSideEffects ::
+  Ptr InlineAsm -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_InlineAsmIsAlignStack" inlineAsmIsAlignStack ::
+  Ptr InlineAsm -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetInlineAsmDialect" getInlineAsmDialect ::
+  Ptr InlineAsm -> IO AsmDialect
+
diff --git a/src/LLVM/Internal/FFI/InlineAssemblyC.cpp b/src/LLVM/Internal/FFI/InlineAssemblyC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/InlineAssemblyC.cpp
@@ -0,0 +1,73 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Function.h"
+#include "llvm-c/Core.h"
+
+#include "LLVM/Internal/FFI/InlineAssembly.h"
+
+using namespace llvm;
+
+namespace llvm {
+static LLVMAsmDialect wrap(InlineAsm::AsmDialect d) {
+	switch(d) {
+#define ENUM_CASE(x) case InlineAsm::AD_ ## x: return LLVMAsmDialect_ ## x;
+LLVM_HS_FOR_EACH_ASM_DIALECT(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMAsmDialect(0);
+	}
+}
+
+static InlineAsm::AsmDialect unwrap(LLVMAsmDialect d) {
+	switch(d) {
+#define ENUM_CASE(x) case LLVMAsmDialect_ ## x: return InlineAsm::AD_ ## x;
+LLVM_HS_FOR_EACH_ASM_DIALECT(ENUM_CASE)
+#undef ENUM_CASE
+	default: return InlineAsm::AsmDialect(0);
+	}
+}
+}
+
+extern "C" {
+
+LLVMValueRef LLVM_Hs_CreateInlineAsm(
+	LLVMTypeRef t,
+	const char *asmStr,
+	const char *constraintsStr,
+	LLVMBool hasSideEffects,
+	LLVMBool isAlignStack,
+	LLVMAsmDialect dialect
+) {
+	return wrap(
+		InlineAsm::get(
+			unwrap<FunctionType>(t), 
+			asmStr,
+			constraintsStr,
+			hasSideEffects,
+			isAlignStack,
+			unwrap(dialect)
+		)
+	);
+}
+
+const char *LLVM_Hs_GetInlineAsmAsmString(LLVMValueRef v) {
+	return unwrap<InlineAsm>(v)->getAsmString().c_str();
+}
+
+const char *LLVM_Hs_GetInlineAsmConstraintString(LLVMValueRef v) {
+	return unwrap<InlineAsm>(v)->getConstraintString().c_str();
+}
+
+LLVMBool LLVM_Hs_InlineAsmHasSideEffects(LLVMValueRef v) {
+	return unwrap<InlineAsm>(v)->hasSideEffects();
+}
+
+LLVMBool LLVM_Hs_InlineAsmIsAlignStack(LLVMValueRef v) {
+	return unwrap<InlineAsm>(v)->isAlignStack();
+}
+
+LLVMAsmDialect LLVM_Hs_GetInlineAsmDialect(LLVMValueRef v) {
+	return wrap(unwrap<InlineAsm>(v)->getDialect());
+}
+
+}
+
diff --git a/src/LLVM/Internal/FFI/Instruction.h b/src/LLVM/Internal/FFI/Instruction.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Instruction.h
@@ -0,0 +1,79 @@
+#ifndef __LLVM_INTERNAL_FFI__INSTRUCTION__H__
+#define __LLVM_INTERNAL_FFI__INSTRUCTION__H__
+
+#include "llvm/Config/llvm-config.h"
+
+#define LLVM_HS_FOR_EACH_ATOMIC_ORDERING(macro) \
+    macro(NotAtomic) \
+    macro(Unordered) \
+    macro(Monotonic) \
+    macro(Acquire) \
+    macro(Release) \
+    macro(AcquireRelease) \
+    macro(SequentiallyConsistent)
+
+#define LLVM_HS_FOR_EACH_RMW_OPERATION(macro) \
+    macro(Xchg) \
+    macro(Add) \
+    macro(Sub) \
+    macro(And) \
+    macro(Nand) \
+    macro(Or) \
+    macro(Xor) \
+    macro(Max) \
+    macro(Min) \
+    macro(UMax) \
+    macro(UMin) \
+    macro(FAdd) \
+    macro(FSub)
+
+typedef enum {
+#define ENUM_CASE(x) LLVMAtomicRMWBinOp_ ## x,
+LLVM_HS_FOR_EACH_RMW_OPERATION(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMAtomicRMWBinOp_;
+
+#define LLVM_HS_FOR_EACH_SYNCRONIZATION_SCOPE(macro) \
+    macro(SingleThread) \
+    macro(System)
+
+typedef enum {
+#define ENUM_CASE(x) LLVM ## x ## SynchronizationScope,
+LLVM_HS_FOR_EACH_SYNCRONIZATION_SCOPE(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMSynchronizationScope;
+
+/* The last parameter to the macro indicates whether the set<param> function takes a boolean argument or not */
+#define LLVM_HS_FOR_EACH_FAST_MATH_FLAG(macro) \
+    macro(AllowReassoc, allowReassoc, F)              \
+    macro(NoNaNs, noNaNs, F)                          \
+    macro(NoInfs, noInfs, F)                          \
+    macro(NoSignedZeros, noSignedZeros, F)            \
+    macro(AllowReciprocal, allowReciprocal, F)        \
+    macro(AllowContract, allowContract, T)            \
+    macro(ApproxFunc, approxFunc, F)
+
+typedef enum {
+#define ENUM_CASE(x,l,takesArg) LLVM ## x ## Bit,
+LLVM_HS_FOR_EACH_FAST_MATH_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMFastMathFlagBit;
+
+typedef enum {
+#define ENUM_CASE(x,l,takesArg) LLVM ## x = (1 << LLVM ## x ## Bit),
+LLVM_HS_FOR_EACH_FAST_MATH_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMFastMathFlags;
+
+#define LLVM_HS_FOR_EACH_TAIL_CALL_KIND(macro) \
+    macro(None)                                       \
+    macro(Tail)                                       \
+    macro(MustTail)                                   \
+    macro(NoTail)
+
+typedef enum {
+#define ENUM_CASE(x) LLVM_Hs_TailCallKind_ ## x,
+LLVM_HS_FOR_EACH_TAIL_CALL_KIND(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_TailCallKind;
+#endif
diff --git a/src/LLVM/Internal/FFI/Instruction.hs b/src/LLVM/Internal/FFI/Instruction.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Instruction.hs
@@ -0,0 +1,192 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances,
+  TemplateHaskell
+  #-}
+module LLVM.Internal.FFI.Instruction where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.Attribute
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.LLVMCTypes
+
+foreign import ccall unsafe "LLVMIsAInstruction" isAInstruction ::
+  Ptr Value -> IO (Ptr Instruction)
+
+newtype COpcode = COpcode CUInt
+
+-- get the C API opcode
+foreign import ccall unsafe "LLVMGetInstructionOpcode" getInstructionOpcode ::
+  Ptr Instruction -> IO COpcode
+
+-- get the C++ API opcode (one less level of mapping than for that from the C API)
+foreign import ccall unsafe "LLVM_Hs_GetInstructionDefOpcode" getInstructionDefOpcode ::
+  Ptr Instruction -> IO CPPOpcode
+
+foreign import ccall unsafe "LLVMGetICmpPredicate" getICmpPredicate ::
+  Ptr Instruction -> IO ICmpPredicate
+
+foreign import ccall unsafe "LLVM_Hs_GetFCmpPredicate" getFCmpPredicate ::
+  Ptr Instruction -> IO FCmpPredicate
+
+foreign import ccall unsafe "LLVM_Hs_GetAbstractCallSiteCallingConvention" getCallSiteCallingConvention ::
+  Ptr Instruction -> IO CallingConvention
+
+foreign import ccall unsafe "LLVM_Hs_SetAbstractCallSiteCallingConvention" setCallSiteCallingConvention ::
+  Ptr Instruction -> CallingConvention -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetTailCallKind" getTailCallKind ::
+  Ptr Instruction -> IO TailCallKind
+
+foreign import ccall unsafe "LLVM_Hs_SetTailCallKind" setTailCallKind ::
+  Ptr Instruction -> TailCallKind -> IO ()
+
+foreign import ccall unsafe "LLVMGetCalledValue" getCallSiteCalledValue ::
+  Ptr Instruction -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVMGetNumArgOperands" getCallSiteNumArgOperands ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_AbstractCallSiteAttributesAtIndex" getCallSiteAttributesAtIndex ::
+  Ptr Instruction -> AttributeIndex -> IO (AttributeSet a)
+
+foreign import ccall unsafe "LLVM_Hs_AbstractCallSiteSetAttributeList" setCallSiteAttributeList ::
+  Ptr Instruction -> AttributeList -> IO ()
+
+foreign import ccall unsafe "LLVMAddIncoming" addIncoming' ::
+  Ptr Instruction -> Ptr (Ptr Value) -> Ptr (Ptr BasicBlock) -> CUInt -> IO ()
+
+addIncoming :: Ptr Instruction -> (CUInt, Ptr (Ptr Value)) -> (CUInt, Ptr (Ptr BasicBlock)) -> IO ()
+addIncoming i (nvs, vs) (nbs, bs)
+  | nbs == nvs = addIncoming' i vs bs nbs
+  | otherwise = error "Number of incoming values and incoming blocks must be equal"
+
+foreign import ccall unsafe "LLVMCountIncoming" countIncoming ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVMGetIncomingValue" getIncomingValue ::
+  Ptr Instruction -> CUInt -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVMGetIncomingBlock" getIncomingBlock ::
+  Ptr Instruction -> CUInt -> IO (Ptr BasicBlock)
+
+
+foreign import ccall unsafe "LLVMAddCase" addCase ::
+  Ptr Instruction -> Ptr Constant -> Ptr BasicBlock -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetSwitchCases" getSwitchCases ::
+  Ptr Instruction -> Ptr (Ptr Constant) -> Ptr (Ptr BasicBlock) -> IO ()
+
+foreign import ccall unsafe "LLVMAddDestination" addDestination ::
+  Ptr Instruction -> Ptr BasicBlock -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetIndirectBrDests" getIndirectBrDests ::
+  Ptr Instruction -> Ptr (Ptr BasicBlock) -> IO ()
+
+
+foreign import ccall unsafe "LLVM_Hs_GetInstrAlignment" getInstrAlignment ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_SetInstrAlignment" setInstrAlignment ::
+  Ptr Instruction -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetAllocaNumElements" getAllocaNumElements ::
+  Ptr Instruction -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_GetAllocatedType" getAllocatedType ::
+  Ptr Instruction -> IO (Ptr Type)
+
+foreign import ccall unsafe "LLVM_Hs_GetAtomicOrdering" getAtomicOrdering ::
+  Ptr Instruction -> IO MemoryOrdering
+
+foreign import ccall unsafe "LLVM_Hs_GetFailureAtomicOrdering" getFailureAtomicOrdering ::
+  Ptr Instruction -> IO MemoryOrdering
+
+foreign import ccall unsafe "LLVM_Hs_GetSynchronizationScope" getSynchronizationScope ::
+  Ptr Instruction -> IO SynchronizationScope
+
+getAtomicity :: Ptr Instruction -> IO (SynchronizationScope, MemoryOrdering)
+getAtomicity i = return (,) `ap` getSynchronizationScope i `ap` getAtomicOrdering i
+
+foreign import ccall unsafe "LLVM_Hs_GetVolatile" getVolatile ::
+  Ptr Instruction -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetInBounds" getInBounds ::
+  Ptr Value -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetAtomicRMWBinOp" getAtomicRMWBinOp ::
+  Ptr Instruction -> IO RMWOperation
+
+foreign import ccall unsafe "LLVM_Hs_CountInstStructureIndices" countInstStructureIndices ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetInstStructureIndices" getInstStructureIndices ::
+  Ptr Instruction -> Ptr CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMAddClause" addClause ::
+  Ptr Instruction -> Ptr Constant -> IO ()
+
+foreign import ccall unsafe "LLVMSetCleanup" setCleanup ::
+  Ptr Instruction -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVMIsCleanup" isCleanup ::
+  Ptr Instruction -> IO LLVMBool
+
+foreign import ccall unsafe "LLVMGetNumClauses" getNumClauses ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVMGetClause" getClause ::
+  Ptr Instruction -> CUInt -> IO (Ptr Constant)
+
+foreign import ccall unsafe "LLVM_Hs_SetMetadata" setMetadata ::
+  Ptr Instruction -> MDKindID -> Ptr MDNode -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetMetadata" getMetadata ::
+  Ptr Instruction -> Ptr MDKindID -> Ptr (Ptr MDNode) -> CUInt -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetShuffleVectorMaskSize" getShuffleVectorMaskSize ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetShuffleVectorMask" getShuffleVectorMask ::
+  Ptr Instruction -> CUInt -> Ptr CInt -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetCleanupPad" getCleanupPad ::
+  Ptr Instruction -> IO (Ptr Instruction)
+
+foreign import ccall unsafe "LLVM_Hs_GetUnwindDest" getUnwindDest ::
+  Ptr Instruction -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVM_Hs_GetParentPad" getParentPad ::
+  Ptr Instruction -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_GetNumArgOperands" getNumArgOperands ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetArgOperand" getArgOperand ::
+  Ptr Instruction -> CUInt -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_CatchSwitch_GetParentPad" catchSwitchGetParentPad ::
+  Ptr Instruction -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_CatchSwitch_GetUnwindDest" catchSwitchGetUnwindDest ::
+  Ptr Instruction -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVM_Hs_CatchSwitch_GetNumHandlers" catchSwitchGetNumHandlers ::
+  Ptr Instruction -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_CatchSwitch_GetHandler" catchSwitchGetHandler ::
+  Ptr Instruction -> CUInt -> IO (Ptr BasicBlock)
+
+foreign import ccall unsafe "LLVM_Hs_CatchSwitch_AddHandler" catchSwitchAddHandler ::
+  Ptr Instruction -> Ptr BasicBlock -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_CatchRet_GetCatchPad" catchRetGetCatchPad ::
+  Ptr Instruction -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_CatchRet_GetSuccessor" catchRetGetSuccessor ::
+  Ptr Instruction -> IO (Ptr BasicBlock)
diff --git a/src/LLVM/Internal/FFI/InstructionC.cpp b/src/LLVM/Internal/FFI/InstructionC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/InstructionC.cpp
@@ -0,0 +1,327 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/AbstractCallSite.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Metadata.h"
+
+#include "llvm-c/Core.h"
+
+#include "LLVM/Internal/FFI/AttributeC.hpp"
+#include "LLVM/Internal/FFI/ErrorHandling.hpp"
+#include "LLVM/Internal/FFI/Instruction.h"
+
+using namespace llvm;
+
+namespace llvm {
+
+static LLVMAtomicOrdering wrap(AtomicOrdering l) {
+	switch(l) {
+#define ENUM_CASE(x) case AtomicOrdering::x: return LLVMAtomicOrdering ## x;
+LLVM_HS_FOR_EACH_ATOMIC_ORDERING(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMAtomicOrdering(0);
+	}
+}
+
+static LLVMSynchronizationScope wrap(SyncScope::ID l) {
+	switch(l) {
+#define ENUM_CASE(x) case SyncScope::x: return LLVM ## x ## SynchronizationScope;
+LLVM_HS_FOR_EACH_SYNCRONIZATION_SCOPE(ENUM_CASE)
+#undef ENUM_CASE
+    default: reportFatalError("Unknown synchronization scope");
+	}
+}
+
+static LLVMAtomicRMWBinOp_ wrap(AtomicRMWInst::BinOp l) {
+	switch(l) {
+#define ENUM_CASE(x) case AtomicRMWInst::x: return LLVMAtomicRMWBinOp_ ## x;
+LLVM_HS_FOR_EACH_RMW_OPERATION(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMAtomicRMWBinOp_(0);
+	}
+}
+
+LLVMFastMathFlags wrap(FastMathFlags f) {
+	unsigned r = 0;
+#define ENUM_CASE(u,l,takesArg) if (f.l()) r |= unsigned(LLVM ## u);
+LLVM_HS_FOR_EACH_FAST_MATH_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    return LLVMFastMathFlags(r);
+}
+
+}
+
+extern "C" {
+
+unsigned LLVM_Hs_GetInstructionDefOpcode(LLVMValueRef val) {
+	return unwrap<Instruction>(val)->getOpcode();
+}
+
+unsigned LLVM_Hs_HasNoSignedWrap(LLVMValueRef val) {
+	return unwrap<OverflowingBinaryOperator>(val)->hasNoSignedWrap();
+}
+
+unsigned LLVM_Hs_HasNoUnsignedWrap(LLVMValueRef val) {
+	return unwrap<OverflowingBinaryOperator>(val)->hasNoUnsignedWrap();
+}
+
+int LLVM_Hs_IsExact(LLVMValueRef val) {
+	return unwrap<PossiblyExactOperator>(val)->isExact();
+}
+
+LLVMFastMathFlags LLVM_Hs_GetFastMathFlags(LLVMValueRef val) {
+	return wrap(unwrap<Instruction>(val)->getFastMathFlags());
+}
+
+void LLVM_Hs_AbstractCallSiteSetAttributeList(LLVMValueRef i, LLVMAttributeListRef attrs) {
+  unwrap<CallBase>(i)->setAttributes(*attrs);
+}
+
+unsigned LLVM_Hs_GetAbstractCallSiteCallingConvention(LLVMValueRef i) {
+  return unsigned(unwrap<CallBase>(i)->getCallingConv());
+}
+
+void LLVM_Hs_SetAbstractCallSiteCallingConvention(LLVMValueRef i, unsigned cc) {
+  unwrap<CallBase>(i)->setCallingConv(llvm::CallingConv::ID(cc));
+}
+
+LLVMAttributeSetRef LLVM_Hs_AbstractCallSiteAttributesAtIndex(LLVMValueRef i, LLVMAttributeIndex idx) {
+    auto cs = unwrap<CallBase>(i);
+    return new AttributeSet(cs->getAttributes().getAttributes(idx));
+}
+
+#define CHECK(name)                                                            \
+    static_assert(unsigned(llvm::CallInst::TCK_##name) ==                      \
+                      unsigned(LLVM_Hs_TailCallKind_##name),              \
+                  "LLVM_Hs_TailCallKind enum out of sync w/ "             \
+                  "llvm::CallInst::TailCallKind for " #name);
+LLVM_HS_FOR_EACH_TAIL_CALL_KIND(CHECK)
+#undef CHECK
+
+unsigned LLVM_Hs_GetTailCallKind(LLVMValueRef i) {
+    return unwrap<CallInst>(i)->getTailCallKind();
+}
+
+void LLVM_Hs_SetTailCallKind(LLVMValueRef i, unsigned kind) {
+    return unwrap<CallInst>(i)->setTailCallKind(llvm::CallInst::TailCallKind(kind));
+}
+
+LLVMValueRef LLVM_Hs_GetAllocaNumElements(LLVMValueRef a) {
+	return wrap(unwrap<AllocaInst>(a)->getArraySize());
+}
+
+LLVMTypeRef LLVM_Hs_GetAllocatedType(LLVMValueRef a) {
+	return wrap(unwrap<AllocaInst>(a)->getAllocatedType());
+}
+
+// ------------------------------------------------------------
+
+#define LLVM_HS_FOR_EACH_ALIGNMENT_INST(macro) \
+	macro(Alloca) \
+	macro(Load) \
+	macro(Store)
+
+unsigned LLVM_Hs_GetInstrAlignment(LLVMValueRef l) {
+	switch(unwrap<Instruction>(l)->getOpcode()) {
+#define ENUM_CASE(n) case Instruction::n: return unwrap<n ## Inst>(l)->getAlignment();
+		LLVM_HS_FOR_EACH_ALIGNMENT_INST(ENUM_CASE)
+#undef ENUM_CASE
+	default: return 0;
+	}
+}
+
+void LLVM_Hs_SetInstrAlignment(LLVMValueRef l, unsigned a) {
+	switch(unwrap<Instruction>(l)->getOpcode()) {
+#define ENUM_CASE(n) case Instruction::n: unwrap<n ## Inst>(l)->setAlignment(Align(a)); break;
+		LLVM_HS_FOR_EACH_ALIGNMENT_INST(ENUM_CASE)
+#undef ENUM_CASE
+	}
+}
+
+// ------------------------------------------------------------
+
+#define LLVM_HS_FOR_EACH_ATOMIC_INST(macro)	\
+	macro(Load,)																		\
+	macro(Store,)																		\
+	macro(Fence,)																		\
+	macro(AtomicCmpXchg,Success)										\
+	macro(AtomicRMW,)
+
+LLVMAtomicOrdering LLVM_Hs_GetAtomicOrdering(LLVMValueRef i) {
+	switch(unwrap<Instruction>(i)->getOpcode()) {
+#define ENUM_CASE(n,s) case Instruction::n: return wrap(unwrap<n ## Inst>(i)->get ## s ## Ordering());
+		LLVM_HS_FOR_EACH_ATOMIC_INST(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMAtomicOrdering(0);
+	}
+}
+
+LLVMAtomicOrdering LLVM_Hs_GetFailureAtomicOrdering(LLVMValueRef i) {
+	switch(unwrap<Instruction>(i)->getOpcode()) {
+	case Instruction::AtomicCmpXchg: return wrap(unwrap<AtomicCmpXchgInst>(i)->getFailureOrdering());
+	default: return LLVMAtomicOrdering(0);
+	}
+}
+
+LLVMSynchronizationScope LLVM_Hs_GetSynchronizationScope(LLVMValueRef i) {
+	switch(unwrap<Instruction>(i)->getOpcode()) {
+#define ENUM_CASE(n,s) case Instruction::n: return wrap(unwrap<n ## Inst>(i)->getSyncScopeID());
+		LLVM_HS_FOR_EACH_ATOMIC_INST(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMSynchronizationScope(0);
+	}
+}
+
+#define LLVM_HS_FOR_EACH_VOLATILITY_INST(macro) \
+	macro(Load) \
+	macro(Store) \
+	macro(AtomicCmpXchg) \
+	macro(AtomicRMW)
+
+LLVMBool LLVM_Hs_GetVolatile(LLVMValueRef i) {
+	switch(unwrap<Instruction>(i)->getOpcode()) {
+#define ENUM_CASE(n) case Instruction::n: return unwrap<n ## Inst>(i)->isVolatile();
+		LLVM_HS_FOR_EACH_VOLATILITY_INST(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMBool(0);
+	}
+}
+
+// ------------------------------------------------------------
+
+LLVMBool LLVM_Hs_GetInBounds(LLVMValueRef i) {
+	return unwrap<GEPOperator>(i)->isInBounds();
+}
+
+LLVMAtomicRMWBinOp_ LLVM_Hs_GetAtomicRMWBinOp(LLVMValueRef i) {
+	return wrap(unwrap<AtomicRMWInst>(i)->getOperation());
+}
+
+LLVMRealPredicate LLVM_Hs_GetFCmpPredicate(LLVMValueRef Inst) {
+	if (FCmpInst *I = dyn_cast<FCmpInst>(unwrap(Inst)))
+		return (LLVMRealPredicate)I->getPredicate();
+	if (ConstantExpr *CE = dyn_cast<ConstantExpr>(unwrap(Inst)))
+		if (CE->getOpcode() == Instruction::FCmp)
+			return (LLVMRealPredicate)CE->getPredicate();
+	return (LLVMRealPredicate)0;
+}
+
+unsigned LLVM_Hs_CountInstStructureIndices(LLVMValueRef v) {
+	if (ExtractValueInst *i = dyn_cast<ExtractValueInst>(unwrap(v))) return i->getNumIndices();
+	if (InsertValueInst *i = dyn_cast<InsertValueInst>(unwrap(v))) return i->getNumIndices();
+	return 0;
+}
+
+void LLVM_Hs_GetInstStructureIndices(LLVMValueRef v, unsigned *is) {
+	ArrayRef<unsigned> a;
+	if (ExtractValueInst *i = dyn_cast<ExtractValueInst>(unwrap(v))) a = i->getIndices();
+	if (InsertValueInst *i = dyn_cast<InsertValueInst>(unwrap(v))) a = i->getIndices();
+	std::copy(a.begin(), a.end(), is);
+}
+
+void LLVM_Hs_GetSwitchCases(
+	LLVMValueRef v,
+	LLVMValueRef *values,
+	LLVMBasicBlockRef *dests
+) {
+	SwitchInst *s = unwrap<SwitchInst>(v);
+	for(SwitchInst::CaseIt i = s->case_begin(); i != s->case_end(); ++i, ++values, ++dests) {
+		*values = wrap(i->getCaseValue());
+		*dests = wrap(i->getCaseSuccessor());
+	}
+}
+
+void LLVM_Hs_GetIndirectBrDests(
+	LLVMValueRef v,
+	LLVMBasicBlockRef *dests
+) {
+	IndirectBrInst *ib = unwrap<IndirectBrInst>(v);
+	for(unsigned i=0; i != ib->getNumDestinations(); ++i, ++dests)
+		*dests = wrap(ib->getDestination(i));
+}
+
+void LLVM_Hs_SetMetadata(LLVMValueRef inst, unsigned kindID, LLVMMetadataRef md) {
+    MDNode *N = md ? unwrap<MDNode>(md) : nullptr;
+    unwrap<Instruction>(inst)->setMetadata(kindID, N);
+}
+
+unsigned LLVM_Hs_GetMetadata(
+	LLVMValueRef i,
+	unsigned *kinds,
+	LLVMMetadataRef *nodes,
+	unsigned nKinds
+) {
+	SmallVector<std::pair<unsigned, MDNode *>, 4> mds;
+	unwrap<Instruction>(i)->getAllMetadata(mds);
+	if (mds.size() <= nKinds) {
+		for(unsigned i=0; i<mds.size(); ++i) {
+			kinds[i] = mds[i].first;
+			nodes[i] = wrap(mds[i].second);
+		}
+	}
+	return mds.size();
+}
+
+unsigned LLVM_Hs_GetShuffleVectorMaskSize(LLVMValueRef i) {
+  return unwrap<ShuffleVectorInst>(i)->getShuffleMask().size();
+}
+
+void LLVM_Hs_GetShuffleVectorMask(LLVMValueRef i, unsigned int numResults, int *result) {
+  const auto& mask = unwrap<ShuffleVectorInst>(i)->getShuffleMask();
+  assert(numResults == mask.size());
+  std::copy(mask.begin(), mask.end(), result);
+}
+
+LLVMValueRef LLVM_Hs_GetCleanupPad(LLVMValueRef i) {
+    return wrap(unwrap<CleanupReturnInst>(i)->getCleanupPad());
+}
+
+LLVMBasicBlockRef LLVM_Hs_GetUnwindDest(LLVMValueRef i) {
+    return wrap(unwrap<CleanupReturnInst>(i)->getUnwindDest());
+}
+
+LLVMValueRef LLVM_Hs_GetParentPad(LLVMValueRef i) {
+    return wrap(unwrap<FuncletPadInst>(i)->getParentPad());
+}
+
+unsigned LLVM_Hs_GetNumArgOperands(LLVMValueRef i) {
+    return unwrap<FuncletPadInst>(i)->getNumArgOperands();
+}
+
+LLVMValueRef LLVM_Hs_GetArgOperand(LLVMValueRef i, unsigned op) {
+    return wrap(unwrap<FuncletPadInst>(i)->getArgOperand(op));
+}
+
+LLVMValueRef LLVM_Hs_CatchSwitch_GetParentPad(LLVMValueRef i) {
+    return wrap(unwrap<CatchSwitchInst>(i)->getParentPad());
+}
+
+LLVMBasicBlockRef LLVM_Hs_CatchSwitch_GetUnwindDest(LLVMValueRef i) {
+    return wrap(unwrap<CatchSwitchInst>(i)->getUnwindDest());
+}
+
+unsigned LLVM_Hs_CatchSwitch_GetNumHandlers(LLVMValueRef i) {
+    return unwrap<CatchSwitchInst>(i)->getNumHandlers();
+}
+
+LLVMBasicBlockRef LLVM_Hs_CatchSwitch_GetHandler(LLVMValueRef instr, unsigned i) {
+    return wrap(*(unwrap<CatchSwitchInst>(instr)->handler_begin() + i));
+}
+
+void LLVM_Hs_CatchSwitch_AddHandler(LLVMValueRef instr, LLVMBasicBlockRef bb) {
+    unwrap<CatchSwitchInst>(instr)->addHandler(unwrap(bb));
+}
+
+LLVMValueRef LLVM_Hs_CatchRet_GetCatchPad(LLVMValueRef i) {
+    return wrap(unwrap<CatchReturnInst>(i)->getCatchPad());
+}
+
+LLVMBasicBlockRef LLVM_Hs_CatchRet_GetSuccessor(LLVMValueRef i) {
+    return wrap(unwrap<CatchReturnInst>(i)->getSuccessor());
+}
+}
diff --git a/src/LLVM/Internal/FFI/InstructionDefs.hsc b/src/LLVM/Internal/FFI/InstructionDefs.hsc
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/InstructionDefs.hsc
@@ -0,0 +1,62 @@
+-- This module translates the instruction data in "llvm/Instruction.def" into a Haskell data structure,
+-- so it may be accessed conveniently with Template Haskell code
+module LLVM.Internal.FFI.InstructionDefs where
+
+import LLVM.Prelude
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+#define FIRST_TERM_INST(num) struct inst { const char *kind; int opcode; const char *name; const char *clas; } insts[] = { { "Terminator", },
+
+#define FIRST_UNARY_INST(num) { "Unary" },
+#define FIRST_BINARY_INST(num) { "Binary" },
+#define FIRST_MEMORY_INST(num) { "Memory" },
+#define FIRST_CAST_INST(num) { "Cast" },
+#define FIRST_OTHER_INST(num) { "Other" },
+#define FIRST_FUNCLETPAD_INST(num) { "FuncletPad" },
+
+#define HANDLE_INST(num,opcode,class) { 0, num, #opcode, #class, },
+
+#define LAST_OTHER_INST(num) { 0, 0, 0, 0, } };
+
+#include "llvm/Config/llvm-config.h"
+
+#include "llvm/IR/Instruction.def"
+
+#{
+define hsc_inject() {                                       \
+  hsc_printf("[");                                       \
+  struct inst *i;                                           \
+  const char *kind = NULL;                                  \
+  int first = 1;                                            \
+  for(i = insts; i->kind || i->opcode; ++i) {               \
+    if (i->kind) { kind = i->kind; continue; }              \
+    if (!first) { hsc_printf("\n   ,"); } else { first = 0; }  \
+    hsc_printf(                                             \
+        " (CPPOpcode %d,\"%s\",\"%s\", %s)",               \
+        i->opcode, i->name, i->clas, kind                   \
+      );                                                    \
+  }                                                         \
+  hsc_printf(" ] ");                                       \
+}
+}
+
+data InstructionKind = Terminator | Unary | Binary | Memory | Cast | FuncletPad | Other
+  deriving (Eq, Ord, Show)
+
+data InstructionDef = InstructionDef {
+    cppOpcode :: CPPOpcode,
+    cAPIName :: String,
+    cAPIClassName :: String,
+    instructionKind :: InstructionKind
+  }
+  deriving (Eq, Ord, Show)
+
+instructionDefs :: [InstructionDef]
+instructionDefs = [
+ InstructionDef o an acn k
+ | (o, an, acn, k) <-
+   #{inject},
+ an /= "UserOp1" && an /= "UserOp2"
+ ]
+
diff --git a/src/LLVM/Internal/FFI/Iterate.hs b/src/LLVM/Internal/FFI/Iterate.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Iterate.hs
@@ -0,0 +1,13 @@
+-- | Functions to help handle LLVM iteration patterns
+module LLVM.Internal.FFI.Iterate where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+
+-- | retrieve a sequence of objects which form a linked list, given an action to
+-- | retrieve the first member and an action to proceed through the list
+getXs :: IO (Ptr a) -> (Ptr a -> IO (Ptr a)) -> IO [Ptr a]
+getXs firstX nextX = walk =<< firstX
+    where walk x | x == nullPtr = return []
+          walk x = (x:) <$> (walk <=< nextX) x
diff --git a/src/LLVM/Internal/FFI/LLVMCTypes.hsc b/src/LLVM/Internal/FFI/LLVMCTypes.hsc
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/LLVMCTypes.hsc
@@ -0,0 +1,378 @@
+{-# LANGUAGE
+  GeneralizedNewtypeDeriving,
+  PatternSynonyms
+  #-}
+-- | Define types which correspond cleanly with some simple types on the C/C++ side.
+-- Encapsulate hsc macro weirdness here, supporting higher-level tricks elsewhere.
+module LLVM.Internal.FFI.LLVMCTypes where
+
+import LLVM.Prelude
+
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#include "llvm-c/Core.h"
+#include "llvm-c/Linker.h"
+#include "llvm-c/Orc.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/TargetMachine.h"
+#include "LLVM/Internal/FFI/Analysis.h"
+#include "LLVM/Internal/FFI/Attribute.h"
+#include "LLVM/Internal/FFI/CallingConvention.h"
+#include "LLVM/Internal/FFI/Constant.h"
+#include "LLVM/Internal/FFI/GlobalValue.h"
+#include "LLVM/Internal/FFI/InlineAssembly.h"
+#include "LLVM/Internal/FFI/Instruction.h"
+#include "LLVM/Internal/FFI/LibFunc.h"
+#include "LLVM/Internal/FFI/Metadata.h"
+#include "LLVM/Internal/FFI/OrcJIT.h"
+#include "LLVM/Internal/FFI/SMDiagnostic.h"
+#include "LLVM/Internal/FFI/Target.h"
+#include "LLVM/Internal/FFI/Type.h"
+#include "LLVM/Internal/FFI/Value.h"
+
+import Language.Haskell.TH.Quote
+
+import Data.Bits
+import Foreign.C
+import Foreign.Storable
+
+#{
+define hsc_inject(l, typ, cons, hprefix, recmac) { \
+  struct { const char *s; unsigned n; } *p, list[] = { LLVM_HS_FOR_EACH_ ## l(recmac) }; \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf(#hprefix "%s :: " #typ "\n", p->s); \
+    hsc_printf(#hprefix "%s = " #cons " %u\n", p->s, p->n); \
+  } \
+  hsc_printf(#hprefix "P :: QuasiQuoter\n" \
+             #hprefix "P = QuasiQuoter {\n" \
+             "  quoteExp = undefined,\n" \
+             "  quotePat = \\s -> dataToPatQ (const Nothing) $ case s of"); \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf("\n    \"%s\" -> " #hprefix "%s", p->s, p->s); \
+  } \
+  hsc_printf("\n    x -> error $ \"bad quasiquoted FFI constant for " #hprefix ": \" ++ x"); \
+  hsc_printf(",\n" \
+             "  quoteType = undefined,\n" \
+             "  quoteDec = undefined\n" \
+             " }\n"); \
+}
+}
+
+#{
+define hsc_patsyn(l, typ, cons, hprefix, recmac) { \
+  struct { const char *s; unsigned n; } *p, list[] = { LLVM_HS_FOR_EACH_ ## l(recmac) }; \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf("pattern " #hprefix "%s :: " #typ "\n", p->s); \
+    hsc_printf("pattern " #hprefix "%s =  " #cons " %u\n", p->s, p->n); \
+  } \
+}
+}
+
+#define DW_OP_Rec(n) { #n, LLVM_Hs_DwOp_##n },
+#{patsyn DW_OP, Word64, , DwOp_, DW_OP_Rec}
+
+newtype Encoding = Encoding CUInt
+  deriving (Data, Show)
+
+#define DW_ATE_Rec(n) { #n, LLVM_Hs_DwAtE_##n },
+#{patsyn DW_ATE, Encoding, Encoding, DwAtE_, DW_ATE_Rec}
+
+newtype DwTag = DwTag Word16
+  deriving (Data, Show)
+
+#define DW_TAG_Rec(n) { #n, LLVM_Hs_DwTag_##n },
+#{patsyn DW_TAG, DwTag, DwTag, DwTag_, DW_TAG_Rec}
+
+newtype DwVirtuality = DwVirtuality Word8
+  deriving (Data, Show)
+
+#define DW_VIRTUALITY_Rec(n) { #n, LLVM_Hs_DwVirtuality_##n },
+#{patsyn DW_VIRTUALITY, DwVirtuality, DwVirtuality, DwVirtuality_, DW_VIRTUALITY_Rec}
+
+deriving instance Data CUInt
+
+newtype LLVMBool = LLVMBool CUInt
+
+-- | If an FFI function returns a value wrapped in 'OwnerTransfered',
+-- this value needs to be freed after it has been processed. Usually
+-- this is done automatically in the 'DecodeM' instance.
+newtype OwnerTransfered a = OwnerTransfered a
+  deriving (Eq, Storable)
+
+newtype NothingAsMinusOne h = NothingAsMinusOne CInt
+  deriving (Storable)
+
+newtype NothingAsEmptyString c = NothingAsEmptyString c
+  deriving (Storable)
+
+newtype CPPOpcode = CPPOpcode CUInt
+  deriving (Eq, Ord, Show, Typeable, Data, Generic)
+
+newtype ICmpPredicate = ICmpPredicate CUInt
+  deriving (Eq, Ord, Show, Typeable, Data, Generic)
+#{enum ICmpPredicate, ICmpPredicate,
+ iCmpPredEQ = LLVMIntEQ,
+ iCmpPredNE = LLVMIntNE,
+ iCmpPredUGT = LLVMIntUGT,
+ iCmpPredUGE = LLVMIntUGE,
+ iCmpPredULT = LLVMIntULT,
+ iCmpPredULE = LLVMIntULE,
+ iCmpPredSGT = LLVMIntSGT,
+ iCmpPredSGE = LLVMIntSGE,
+ iCmpPredSLT = LLVMIntSLT,
+ iCmpPredSLE = LLVMIntSLE
+}
+
+newtype FCmpPredicate = FCmpPredicate CUInt
+  deriving (Eq, Ord, Show, Typeable, Data, Generic)
+#{enum FCmpPredicate, FCmpPredicate,
+ fCmpPredFalse = LLVMRealPredicateFalse,
+ fCmpPredOEQ = LLVMRealOEQ,
+ fCmpPredOGT = LLVMRealOGT,
+ fCmpPredOGE = LLVMRealOGE,
+ fCmpPredOLT = LLVMRealOLT,
+ fCmpPredOLE = LLVMRealOLE,
+ fCmpPredONE = LLVMRealONE,
+ fCmpPredORD = LLVMRealORD,
+ fCmpPredUNO = LLVMRealUNO,
+ fCmpPredUEQ = LLVMRealUEQ,
+ fCmpPredUGT = LLVMRealUGT,
+ fCmpPredUGE = LLVMRealUGE,
+ fCmpPredULT = LLVMRealULT,
+ fCmpPredULE = LLVMRealULE,
+ fCmpPredUNE = LLVMRealUNE,
+ fcmpPredTrue = LLVMRealPredicateTrue
+}
+
+newtype MDKindID = MDKindID CUInt
+  deriving (Storable)
+
+newtype MDSubclassID = MDSubclassID CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define MDSID_Rec(n) { #n, n ## Kind },
+#{inject MDNODE_SUBCLASS, MDSubclassID, MDSubclassID, mdSubclassId, MDSID_Rec}
+
+newtype FastMathFlags = FastMathFlags CUInt
+  deriving (Eq, Ord, Show, Typeable, Data, Num, Bits, Generic)
+#define FMF_Rec(n,l,ignored) { #n, LLVM ## n, },
+#{inject FAST_MATH_FLAG, FastMathFlags, FastMathFlags, fastMathFlags, FMF_Rec}
+
+newtype MemoryOrdering = MemoryOrdering CUInt
+  deriving (Eq, Show, Typeable, Data, Generic)
+#define MO_Rec(n) { #n, LLVMAtomicOrdering ## n },
+#{inject ATOMIC_ORDERING, MemoryOrdering, MemoryOrdering, memoryOrdering, MO_Rec}
+
+newtype UnnamedAddr = UnnamedAddr CUInt
+  deriving (Eq, Show, Typeable, Data, Generic)
+#define UA_Rec(n) { #n, LLVM ## n ## UnnamedAddr },
+#{inject UNNAMED_ADDR, UnnamedAddr, UnnamedAddr, unnamedAddr, UA_Rec}
+
+newtype SynchronizationScope = SynchronizationScope CUInt
+  deriving (Eq, Show, Typeable, Data, Generic)
+#define SS_Rec(n) { #n, LLVM ## n ## SynchronizationScope },
+#{inject SYNCRONIZATION_SCOPE, SynchronizationScope, SynchronizationScope, synchronizationScope, SS_Rec}
+
+newtype TailCallKind = TailCallKind CUInt
+  deriving (Eq, Show, Typeable, Data, Generic)
+#define TCK_Rec(n) { #n, LLVM_Hs_TailCallKind_ ## n },
+#{inject TAIL_CALL_KIND, TailCallKind, TailCallKind, tailCallKind, TCK_Rec}
+
+newtype Linkage = Linkage CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define LK_Rec(n) { #n, LLVM ## n ## Linkage },
+#{inject LINKAGE, Linkage, Linkage, linkage, LK_Rec}
+
+newtype Visibility = Visibility CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define VIS_Rec(n) { #n, LLVM ## n ## Visibility },
+#{inject VISIBILITY, Visibility, Visibility, visibility, VIS_Rec}
+
+newtype COMDATSelectionKind = COMDATSelectionKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define CSK(n) { #n, LLVM_Hs_COMDAT_Selection_Kind_ ## n },
+#{inject COMDAT_SELECTION_KIND, COMDATSelectionKind, COMDATSelectionKind, comdatSelectionKind, CSK}
+
+newtype DLLStorageClass = DLLStorageClass CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define DLLSC_Rec(n) { #n, LLVM ## n ## StorageClass },
+#{inject DLL_STORAGE_CLASS, DLLStorageClass, DLLStorageClass, dllStorageClass, DLLSC_Rec}
+
+newtype CallingConvention = CallingConvention CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define CC_Rec(l, n) { #l, LLVM_Hs_CallingConvention_ ## l },
+#{inject CALLING_CONVENTION, CallingConvention, CallingConvention, callingConvention, CC_Rec}
+
+newtype ThreadLocalMode = ThreadLocalMode CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define TLS_Rec(n) { #n, LLVM ## n },
+#{inject THREAD_LOCAL_MODE, ThreadLocalMode, ThreadLocalMode, threadLocalMode, TLS_Rec}
+
+newtype ValueSubclassId = ValueSubclassId CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define VSID_Rec(n) { #n, LLVM ## n ## SubclassId },
+#{inject VALUE_SUBCLASS, ValueSubclassId, ValueSubclassId, valueSubclassId, VSID_Rec}
+
+newtype DiagnosticKind = DiagnosticKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define DK_Rec(n) { #n, LLVMDiagnosticKind ## n },
+#{inject DIAGNOSTIC_KIND, DiagnosticKind, DiagnosticKind, diagnosticKind, DK_Rec}
+
+newtype AsmDialect = AsmDialect CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define ASM_Rec(n) { #n, LLVMAsmDialect_ ## n },
+#{inject ASM_DIALECT, AsmDialect, AsmDialect, asmDialect, ASM_Rec}
+
+newtype RMWOperation = RMWOperation CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define RMWOp_Rec(n) { #n, LLVMAtomicRMWBinOp_ ## n },
+#{inject RMW_OPERATION, RMWOperation, RMWOperation, rmwOperation, RMWOp_Rec}
+
+newtype RelocModel = RelocModel CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define RM_Rec(n,m) { #n, LLVMReloc ## n },
+#{inject RELOC_MODEL, RelocModel, RelocModel, relocModel, RM_Rec}
+
+newtype CodeModel = CodeModel CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define CM_Rec(n) { #n, LLVMCodeModel ## n },
+#{inject CODE_MODEL, CodeModel, CodeModel, codeModel, CM_Rec}
+
+newtype CodeGenOptLevel = CodeGenOptLevel CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define CGOL_Rec(n) { #n, LLVMCodeGenLevel ## n },
+#{inject CODE_GEN_OPT_LEVEL, CodeGenOptLevel, CodeGenOptLevel, codeGenOptLevel, CGOL_Rec}
+
+newtype CodeGenFileType = CodeGenFileType CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define CGFT_Rec(n) { #n, LLVM ## n ## File },
+#{inject CODE_GEN_FILE_TYPE, CodeGenFileType, CodeGenFileType, codeGenFileType, CGFT_Rec}
+
+newtype FloatABIType = FloatABIType CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define FAT_Rec(n) { #n, LLVM_Hs_FloatABI_ ## n },
+#{inject FLOAT_ABI, FloatABIType, FloatABIType, floatABI, FAT_Rec}
+
+newtype FPOpFusionMode = FPOpFusionMode CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define FPOFM_Rec(n) { #n, LLVM_Hs_FPOpFusionMode_ ## n },
+#{inject FP_OP_FUSION_MODE, FPOpFusionMode, FPOpFusionMode, fpOpFusionMode, FPOFM_Rec}
+
+newtype ThreadModel = ThreadModel CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define TM_Rec(n) { #n, LLVM_Hs_ThreadModel_ ## n },
+#{inject THREAD_MODEL, ThreadModel, ThreadModel, threadModel, TM_Rec}
+
+newtype EABI = EABI CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define EABI_Rec(n) { #n, LLVM_Hs_EABI_ ## n },
+#{inject EABI, EABI, EABI, eabiVersion, EABI_Rec}
+
+newtype DebuggerKind = DebuggerKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define DBGK_Rec(n) { #n, LLVM_Hs_DebuggerKind_ ## n },
+#{inject DEBUGGER_KIND, DebuggerKind, DebuggerKind, debuggerKind, DBGK_Rec}
+
+newtype FPDenormalMode = FPDenormalMode CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define FPDM_Rec(n) { #n, LLVM_Hs_FPDenormalMode_ ## n },
+#{inject FP_DENORMAL_MODE, FPDenormalMode, FPDenormalMode, fpDenormalMode, FPDM_Rec}
+
+newtype ExceptionHandling = ExceptionHandling CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define EH_Rec(n) { #n, LLVM_Hs_ExceptionHandling_ ## n },
+#{inject EXCEPTION_HANDLING, ExceptionHandling, ExceptionHandling, exceptionHandling, EH_Rec}
+
+newtype TargetOptionFlag = TargetOptionFlag CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define TOF_Rec(n) { #n, LLVM_Hs_TargetOptionFlag_ ## n },
+#{inject TARGET_OPTION_FLAG, TargetOptionFlag, TargetOptionFlag, targetOptionFlag, TOF_Rec}
+
+newtype MCTargetOptionFlag = MCTargetOptionFlag CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define MCTOF_Rec(n) { #n, LLVM_Hs_MCTargetOptionFlag_ ## n },
+#{inject MC_TARGET_OPTION_FLAG, MCTargetOptionFlag, MCTargetOptionFlag, mcTargetOptionFlag, MCTOF_Rec}
+
+newtype DebugCompressionType = DebugCompressionType CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define DCT_Rec(n) { #n, LLVM_Hs_DebugCompressionType_ ## n },
+#{inject DEBUG_COMPRESSION_TYPE, DebugCompressionType, DebugCompressionType, debugCompressionType, DCT_Rec}
+
+newtype TypeKind = TypeKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define TK_Rec(n) { #n, LLVM ## n ## TypeKind },
+#{inject TYPE_KIND, TypeKind, TypeKind, typeKind, TK_Rec}
+
+#define COMMA ,
+#define IF_T(z) z
+#define IF_F(z)
+#define IF2(x) IF_ ## x
+#define IF(x) IF2(x)
+#define OR_TT T
+#define OR_TF T
+#define OR_FT T
+#define OR_FF F
+#define OR(x,y) OR_ ## x ## y
+newtype ParameterAttributeKind = ParameterAttributeKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define PAK_Rec(n,p,r,f) IF(OR(p,r))({ #n COMMA LLVM_Hs_AttributeKind_ ## n} COMMA)
+#{inject ATTRIBUTE_KIND, ParameterAttributeKind, ParameterAttributeKind, parameterAttributeKind, PAK_Rec}
+
+newtype FunctionAttributeKind = FunctionAttributeKind CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define FAK_Rec(n,p,r,f) IF(f)({ #n COMMA LLVM_Hs_AttributeKind_ ## n} COMMA)
+#{inject ATTRIBUTE_KIND, FunctionAttributeKind, FunctionAttributeKind, functionAttributeKind, FAK_Rec}
+
+newtype FloatSemantics = FloatSemantics CUInt
+  deriving (Eq, Read, Show, Typeable, Data, Generic)
+#define FS_Rec(n) { #n, LLVMFloatSemantics ## n },
+#{inject FLOAT_SEMANTICS, FloatSemantics, FloatSemantics, floatSemantics, FS_Rec}
+
+newtype VerifierFailureAction = VerifierFailureAction CUInt
+  deriving (Eq, Read, Show, Bits, Typeable, Data, Num, Generic)
+#define VFA_Rec(n) { #n, LLVM ## n ## Action },
+#{inject VERIFIER_FAILURE_ACTION, VerifierFailureAction, VerifierFailureAction, verifierFailureAction, VFA_Rec}
+
+newtype LibFunc = LibFunc CUInt
+  deriving (Eq, Read, Show, Bits, Typeable, Data, Num, Storable, Generic)
+#define LF_Rec(n) { #n, LLVMLibFunc__ ## n },
+#{inject LIB_FUNC, LibFunc, LibFunc, libFunc__, LF_Rec}
+
+newtype JITSymbolFlags = JITSymbolFlags CUInt
+  deriving (Eq, Read, Show, Bits, Typeable, Data, Num, Storable, Generic)
+
+#define SF_Rec(n) { #n, LLVMJITSymbolFlag ## n },
+#{inject JIT_SYMBOL_FLAG, JITSymbolFlags, JITSymbolFlags, jitSymbolFlags, SF_Rec}
+
+newtype ChecksumKind = ChecksumKind CUInt
+  deriving (Data, Show)
+
+newtype Macinfo = Macinfo CUInt
+  deriving (Data, Show)
+
+pattern DW_Macinfo_Define :: Macinfo
+pattern DW_Macinfo_Define = Macinfo 0x01
+pattern DW_Macinfo_Undef :: Macinfo
+pattern DW_Macinfo_Undef = Macinfo 0x02
+
+newtype DebugEmissionKind = DebugEmissionKind CUInt
+  deriving (Data, Show)
+
+pattern NoDebug :: DebugEmissionKind
+pattern NoDebug = DebugEmissionKind 0
+pattern FullDebug :: DebugEmissionKind
+pattern FullDebug = DebugEmissionKind 1
+pattern LineTablesOnly :: DebugEmissionKind
+pattern LineTablesOnly = DebugEmissionKind 2
+
+newtype DebugNameTableKind = DebugNameTableKind CUInt
+  deriving (Data, Show)
+
+pattern NameTableKindDefault :: DebugNameTableKind
+pattern NameTableKindDefault = DebugNameTableKind 0
+
+pattern NameTableKindGNU :: DebugNameTableKind
+pattern NameTableKindGNU = DebugNameTableKind 1
+
+pattern NameTableKindNone :: DebugNameTableKind
+pattern NameTableKindNone = DebugNameTableKind 2
diff --git a/src/LLVM/Internal/FFI/LibFunc.h b/src/LLVM/Internal/FFI/LibFunc.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/LibFunc.h
@@ -0,0 +1,332 @@
+#ifndef __LLVM_INTERNAL_FFI__LIB_FUNC__H__
+#define __LLVM_INTERNAL_FFI__LIB_FUNC__H__
+
+#define LLVM_HS_FOR_EACH_LIB_FUNC(macro)		\
+	macro(under_IO_getc)													\
+	macro(under_IO_putc)													\
+	macro(ZdaPv)																	\
+	macro(ZdaPvRKSt9nothrow_t)										\
+	macro(ZdlPv)																	\
+	macro(ZdlPvRKSt9nothrow_t)										\
+	macro(Znaj)																		\
+	macro(ZnajRKSt9nothrow_t)											\
+	macro(Znam)																		\
+	macro(ZnamRKSt9nothrow_t)											\
+	macro(Znwj)																		\
+	macro(ZnwjRKSt9nothrow_t)											\
+	macro(Znwm)																		\
+	macro(ZnwmRKSt9nothrow_t)											\
+	macro(cospi)																	\
+	macro(cospif)																	\
+	macro(cxa_atexit)															\
+	macro(cxa_guard_abort)												\
+	macro(cxa_guard_acquire)											\
+	macro(cxa_guard_release)											\
+	macro(dunder_isoc99_scanf)										\
+	macro(dunder_isoc99_sscanf)										\
+	macro(memcpy_chk)															\
+	macro(sincospi_stret)													\
+	macro(sincospif_stret)												\
+	macro(sinpi)																	\
+	macro(sinpif)																	\
+	macro(sqrt_finite)														\
+	macro(sqrtf_finite)														\
+	macro(sqrtl_finite)														\
+	macro(dunder_strdup)													\
+	macro(dunder_strndup)													\
+	macro(dunder_strtok_r)												\
+	macro(abs)																		\
+	macro(access)																	\
+	macro(acos)																		\
+	macro(acosf)																	\
+	macro(acosh)																	\
+	macro(acoshf)																	\
+	macro(acoshl)																	\
+	macro(acosl)																	\
+	macro(asin)																		\
+	macro(asinf)																	\
+	macro(asinh)																	\
+	macro(asinhf)																	\
+	macro(asinhl)																	\
+	macro(asinl)																	\
+	macro(atan)																		\
+	macro(atan2)																	\
+	macro(atan2f)																	\
+	macro(atan2l)																	\
+	macro(atanf)																	\
+	macro(atanh)																	\
+	macro(atanhf)																	\
+	macro(atanhl)																	\
+	macro(atanl)																	\
+	macro(atof)																		\
+	macro(atoi)																		\
+	macro(atol)																		\
+	macro(atoll)																	\
+	macro(bcmp)																		\
+	macro(bcopy)																	\
+	macro(bzero)																	\
+	macro(calloc)																	\
+	macro(cbrt)																		\
+	macro(cbrtf)																	\
+	macro(cbrtl)																	\
+	macro(ceil)																		\
+	macro(ceilf)																	\
+	macro(ceill)																	\
+	macro(chmod)																	\
+	macro(chown)																	\
+	macro(clearerr)																\
+	macro(closedir)																\
+	macro(copysign)																\
+	macro(copysignf)															\
+	macro(copysignl)															\
+	macro(cos)																		\
+	macro(cosf)																		\
+	macro(cosh)																		\
+	macro(coshf)																	\
+	macro(coshl)																	\
+	macro(cosl)																		\
+	macro(ctermid)																\
+	macro(exp)																		\
+	macro(exp10)																	\
+	macro(exp10f)																	\
+	macro(exp10l)																	\
+	macro(exp2)																		\
+	macro(exp2f)																	\
+	macro(exp2l)																	\
+	macro(expf)																		\
+	macro(expl)																		\
+	macro(expm1)																	\
+	macro(expm1f)																	\
+	macro(expm1l)																	\
+	macro(fabs)																		\
+	macro(fabsf)																	\
+	macro(fabsl)																	\
+	macro(fclose)																	\
+	macro(fdopen)																	\
+	macro(feof)																		\
+	macro(ferror)																	\
+	macro(fflush)																	\
+	macro(ffs)																		\
+	macro(ffsl)																		\
+	macro(ffsll)																	\
+	macro(fgetc)																	\
+	macro(fgetpos)																\
+	macro(fgets)																	\
+	macro(fileno)																	\
+	macro(fiprintf)																\
+	macro(flockfile)															\
+	macro(floor)																	\
+	macro(floorf)																	\
+	macro(floorl)																	\
+	macro(fmax)																		\
+	macro(fmaxf)																	\
+	macro(fmaxl)																	\
+	macro(fmin)																		\
+	macro(fminf)																	\
+	macro(fminl)																	\
+	macro(fmod)																		\
+	macro(fmodf)																	\
+	macro(fmodl)																	\
+	macro(fopen)																	\
+	macro(fopen64)																\
+	macro(fprintf)																\
+	macro(fputc)																	\
+	macro(fputs)																	\
+	macro(fread)																	\
+	macro(free)																		\
+	macro(frexp)																	\
+	macro(frexpf)																	\
+	macro(frexpl)																	\
+	macro(fscanf)																	\
+	macro(fseek)																	\
+	macro(fseeko)																	\
+	macro(fseeko64)																\
+	macro(fsetpos)																\
+	macro(fstat)																	\
+	macro(fstat64)																\
+	macro(fstatvfs)																\
+	macro(fstatvfs64)															\
+	macro(ftell)																	\
+	macro(ftello)																	\
+	macro(ftello64)																\
+	macro(ftrylockfile)														\
+	macro(funlockfile)														\
+	macro(fwrite)																	\
+	macro(getc)																		\
+	macro(getc_unlocked)													\
+	macro(getchar)																\
+	macro(getenv)																	\
+	macro(getitimer)															\
+	macro(getlogin_r)															\
+	macro(getpwnam)																\
+	macro(gets)																		\
+	macro(gettimeofday)														\
+	macro(htonl)																	\
+	macro(htons)																	\
+	macro(iprintf)																\
+	macro(isascii)																\
+	macro(isdigit)																\
+	macro(labs)																		\
+	macro(lchown)																	\
+	macro(ldexp)																	\
+	macro(ldexpf)																	\
+	macro(ldexpl)																	\
+	macro(llabs)																	\
+	macro(log)																		\
+	macro(log10)																	\
+	macro(log10f)																	\
+	macro(log10l)																	\
+	macro(log1p)																	\
+	macro(log1pf)																	\
+	macro(log1pl)																	\
+	macro(log2)																		\
+	macro(log2f)																	\
+	macro(log2l)																	\
+	macro(logb)																		\
+	macro(logbf)																	\
+	macro(logbl)																	\
+	macro(logf)																		\
+	macro(logl)																		\
+	macro(lstat)																	\
+	macro(lstat64)																\
+	macro(malloc)																	\
+	macro(memalign)																\
+	macro(memccpy)																\
+	macro(memchr)																	\
+	macro(memcmp)																	\
+	macro(memcpy)																	\
+	macro(memmove)																\
+	macro(memrchr)																\
+	macro(memset)																	\
+	macro(memset_pattern16)												\
+	macro(mkdir)																	\
+	macro(mktime)																	\
+	macro(modf)																		\
+	macro(modff)																	\
+	macro(modfl)																	\
+	macro(nearbyint)															\
+	macro(nearbyintf)															\
+	macro(nearbyintl)															\
+	macro(ntohl)																	\
+	macro(ntohs)																	\
+	macro(open)																		\
+	macro(open64)																	\
+	macro(opendir)																\
+	macro(pclose)																	\
+	macro(perror)																	\
+	macro(popen)																	\
+	macro(posix_memalign)													\
+	macro(pow)																		\
+	macro(powf)																		\
+	macro(powl)																		\
+	macro(pread)																	\
+	macro(printf)																	\
+	macro(putc)																		\
+	macro(putchar)																\
+	macro(puts)																		\
+	macro(pwrite)																	\
+	macro(qsort)																	\
+	macro(read)																		\
+	macro(readlink)																\
+	macro(realloc)																\
+	macro(reallocf)																\
+	macro(realpath)																\
+	macro(remove)																	\
+	macro(rename)																	\
+	macro(rewind)																	\
+	macro(rint)																		\
+	macro(rintf)																	\
+	macro(rintl)																	\
+	macro(rmdir)																	\
+	macro(round)																	\
+	macro(roundf)																	\
+	macro(roundl)																	\
+	macro(scanf)																	\
+	macro(setbuf)																	\
+	macro(setitimer)															\
+	macro(setvbuf)																\
+	macro(sin)																		\
+	macro(sinf)																		\
+	macro(sinh)																		\
+	macro(sinhf)																	\
+	macro(sinhl)																	\
+	macro(sinl)																		\
+	macro(siprintf)																\
+	macro(snprintf)																\
+	macro(sprintf)																\
+	macro(sqrt)																		\
+	macro(sqrtf)																	\
+	macro(sqrtl)																	\
+	macro(sscanf)																	\
+	macro(stat)																		\
+	macro(stat64)																	\
+	macro(statvfs)																\
+	macro(statvfs64)															\
+	macro(stpcpy)																	\
+	macro(stpncpy)																\
+	macro(strcasecmp)															\
+	macro(strcat)																	\
+	macro(strchr)																	\
+	macro(strcmp)																	\
+	macro(strcoll)																\
+	macro(strcpy)																	\
+	macro(strcspn)																\
+	macro(strdup)																	\
+	macro(strlen)																	\
+	macro(strncasecmp)														\
+	macro(strncat)																\
+	macro(strncmp)																\
+	macro(strncpy)																\
+	macro(strndup)																\
+	macro(strnlen)																\
+	macro(strpbrk)																\
+	macro(strrchr)																\
+	macro(strspn)																	\
+	macro(strstr)																	\
+	macro(strtod)																	\
+	macro(strtof)																	\
+	macro(strtok)																	\
+	macro(strtok_r)																\
+	macro(strtol)																	\
+	macro(strtold)																\
+	macro(strtoll)																\
+	macro(strtoul)																\
+	macro(strtoull)																\
+	macro(strxfrm)																\
+	macro(system)																	\
+	macro(tan)																		\
+	macro(tanf)																		\
+	macro(tanh)																		\
+	macro(tanhf)																	\
+	macro(tanhl)																	\
+	macro(tanl)																		\
+	macro(times)																	\
+	macro(tmpfile)																\
+	macro(tmpfile64)															\
+	macro(toascii)																\
+	macro(trunc)																	\
+	macro(truncf)																	\
+	macro(truncl)																	\
+	macro(uname)																	\
+	macro(ungetc)																	\
+	macro(unlink)																	\
+	macro(unsetenv)																\
+	macro(utime)																	\
+	macro(utimes)																	\
+	macro(valloc)																	\
+	macro(vfprintf)																\
+	macro(vfscanf)																\
+	macro(vprintf)																\
+	macro(vscanf)																	\
+	macro(vsnprintf)															\
+	macro(vsprintf)																\
+	macro(vsscanf)																\
+	macro(write)
+
+typedef enum {
+#define ENUM_CASE(x) LLVMLibFunc__ ## x,
+LLVM_HS_FOR_EACH_LIB_FUNC(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMLibFunc;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/MemoryBuffer.hs b/src/LLVM/Internal/FFI/MemoryBuffer.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/MemoryBuffer.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.MemoryBuffer where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+data MemoryBuffer
+
+foreign import ccall unsafe "LLVMCreateMemoryBufferWithContentsOfFile" createMemoryBufferWithContentsOfFile ::
+  Ptr CChar -> Ptr (Ptr MemoryBuffer) -> Ptr (OwnerTransfered CString) -> IO LLVMBool
+
+foreign import ccall unsafe "LLVMCreateMemoryBufferWithMemoryRange" createMemoryBufferWithMemoryRange ::
+  Ptr CChar -> CSize -> CString -> LLVMBool -> IO (Ptr MemoryBuffer)
+
+foreign import ccall unsafe "LLVMGetBufferStart" getBufferStart ::
+  Ptr MemoryBuffer -> IO (Ptr CChar)
+
+foreign import ccall unsafe "LLVMGetBufferSize" getBufferSize ::
+  Ptr MemoryBuffer -> IO CSize
+
+foreign import ccall unsafe "LLVMDisposeMemoryBuffer" disposeMemoryBuffer ::
+  Ptr MemoryBuffer -> IO ()
diff --git a/src/LLVM/Internal/FFI/Metadata.h b/src/LLVM/Internal/FFI/Metadata.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Metadata.h
@@ -0,0 +1,142 @@
+#ifndef __LLVM_INTERNAL_FFI__METADATA__H__
+#define __LLVM_INTERNAL_FFI__METADATA__H__
+
+enum {
+#define HANDLE_METADATA_LEAF(CLASS) CLASS##Kind,
+#include "llvm/IR/Metadata.def"
+#undef HANDLE_METADATA_LEAF
+} MetadataSubclassId;
+
+#define LLVM_HS_FOR_EACH_MDNODE_SUBCLASS(macro) \
+  macro(MDString) \
+  macro(ConstantAsMetadata) \
+  macro(LocalAsMetadata) \
+  macro(DistinctMDOperandPlaceholder) \
+  macro(MDTuple) \
+  macro(DILocation) \
+  macro(DIExpression) \
+  macro(DIGlobalVariableExpression) \
+  macro(GenericDINode) \
+  macro(DISubrange) \
+  macro(DIEnumerator) \
+  macro(DIBasicType) \
+  macro(DIDerivedType) \
+  macro(DICompositeType) \
+  macro(DISubroutineType) \
+  macro(DIFile) \
+  macro(DICompileUnit) \
+  macro(DISubprogram) \
+  macro(DILexicalBlock) \
+  macro(DILexicalBlockFile) \
+  macro(DINamespace) \
+  macro(DIModule) \
+  macro(DITemplateTypeParameter) \
+  macro(DITemplateValueParameter) \
+  macro(DIGlobalVariable) \
+  macro(DILocalVariable) \
+  macro(DIObjCProperty) \
+  macro(DIImportedEntity) \
+  macro(DIMacro) \
+  macro(DIMacroFile)
+
+enum LLVM_Hs_DwOp {
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) LLVM_Hs_DwOp_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DW_OP
+    LLVM_Hs_DwOp_LLVM_fragment = 0x1000
+};
+
+#define LLVM_HS_FOR_EACH_DW_OP(macro) \
+    macro(and)                        \
+    macro(bregx)                      \
+    macro(constu)                     \
+    macro(deref)                      \
+    macro(div)                        \
+    macro(dup)                        \
+    macro(lit0)                       \
+    macro(LLVM_fragment)              \
+    macro(minus)                      \
+    macro(mod)                        \
+    macro(mul)                        \
+    macro(not)                        \
+    macro(or)                         \
+    macro(plus)                       \
+    macro(plus_uconst)                \
+    macro(push_object_address)        \
+    macro(shl)                        \
+    macro(shr)                        \
+    macro(shra)                       \
+    macro(stack_value)                \
+    macro(swap)                       \
+    macro(xderef)                     \
+    macro(xor)
+
+enum LLVM_Hs_DwAtE {
+#define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR) LLVM_Hs_DwAtE_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DW_ATE
+};
+
+#define LLVM_HS_FOR_EACH_DW_ATE(macro) \
+    macro(address)                     \
+    macro(boolean)                     \
+    macro(complex_float)               \
+    macro(float)                       \
+    macro(signed)                      \
+    macro(signed_char)                 \
+    macro(unsigned)                    \
+    macro(unsigned_char)               \
+    macro(imaginary_float)             \
+    macro(packed_decimal)              \
+    macro(numeric_string)              \
+    macro(edited)                      \
+    macro(signed_fixed)                \
+    macro(unsigned_fixed)              \
+    macro(decimal_float)               \
+    macro(UTF)                         \
+    macro(UCS)                         \
+    macro(ASCII)
+
+enum LLVM_Hs_DwTag {
+#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) LLVM_Hs_DwTag_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DW_TAG
+};
+
+#define LLVM_HS_FOR_EACH_DW_TAG(macro) \
+    macro(imported_module) \
+    macro(imported_declaration) \
+    macro(typedef) \
+    macro(pointer_type) \
+    macro(ptr_to_member_type) \
+    macro(reference_type) \
+    macro(rvalue_reference_type) \
+    macro(const_type) \
+    macro(volatile_type) \
+    macro(restrict_type) \
+    macro(atomic_type) \
+    macro(member) \
+    macro(inheritance) \
+    macro(friend) \
+    macro(base_type) \
+    macro(unspecified_type) \
+    macro(template_value_parameter) \
+    macro(GNU_template_template_param) \
+    macro(GNU_template_parameter_pack) \
+    macro(array_type) \
+    macro(enumeration_type) \
+    macro(structure_type) \
+    macro(class_type) \
+    macro(union_type)
+
+enum LLVM_Hs_DwVirtuality {
+#define HANDLE_DW_VIRTUALITY(ID, NAME) LLVM_Hs_DwVirtuality_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DW_VIRTUALITY
+};
+
+#define LLVM_HS_FOR_EACH_DW_VIRTUALITY(macro) \
+    macro(none) \
+    macro(virtual) \
+    macro(pure_virtual)
+#endif
diff --git a/src/LLVM/Internal/FFI/Metadata.hs b/src/LLVM/Internal/FFI/Metadata.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Metadata.hs
@@ -0,0 +1,655 @@
+{-#
+  LANGUAGE
+  ForeignFunctionInterface
+  #-}
+
+module LLVM.Internal.FFI.Metadata where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.LLVMCTypes
+
+newtype DIFlags = DIFlags Word32
+  deriving (Show, Eq)
+
+data DITemplateParameterArray
+
+-- | A 'TupleArray a' stores an array of elements of type 'Ptr a' using an 'MDTuple'.
+newtype TupleArray a = TupleArray (Ptr MDTuple)
+
+foreign import ccall unsafe "LLVM_Hs_IsAMDString" isAMDString ::
+  Ptr Metadata -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_IsAMDNode" isAMDNode ::
+  Ptr Metadata -> IO (Ptr MDNode)
+
+foreign import ccall unsafe "LLVM_Hs_IsAMDValue" isAMDValue ::
+  Ptr Metadata -> IO (Ptr MDValue)
+
+foreign import ccall unsafe "LLVM_Hs_IsAMetadataOperand" isAMetadataOperand ::
+  Ptr Value -> IO (Ptr MetadataAsVal)
+
+foreign import ccall unsafe "LLVM_Hs_GetMetadataClassId" getMetadataClassId ::
+  Ptr MDNode -> IO (MDSubclassID)
+
+foreign import ccall unsafe "LLVM_Hs_IsADIVariable" isADIVariable ::
+  Ptr Metadata -> IO (Ptr DIVariable)
+
+foreign import ccall unsafe "LLVM_Hs_IsADIExpression" isADIExpression ::
+  Ptr Metadata -> IO (Ptr DIExpression)
+
+-- DILocation
+
+foreign import ccall unsafe "LLVM_Hs_DILocation_GetLine" getDILocationLine ::
+  Ptr DILocation -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DILocation_GetColumn" getDILocationColumn ::
+  Ptr DILocation -> IO Word16
+
+foreign import ccall unsafe "LLVM_Hs_DILocation_GetScope" getDILocationScope ::
+  Ptr DILocation -> IO (Ptr DILocalScope)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DILocation" getDILocation ::
+  Ptr Context -> Word32 -> Word16 -> Ptr DILocalScope -> IO (Ptr DILocation)
+
+foreign import ccall unsafe "LLVM_Hs_GetMDValue" getMDValue ::
+  Ptr MDValue -> IO (Ptr Value)
+
+{-
+foreign import ccall unsafe "LLVM_Hs_DumpMetadata" dumpMetadata ::
+  Ptr Metadata -> IO ()
+-}
+
+foreign import ccall unsafe "LLVM_Hs_GetMetadataOperand" getMetadataOperand ::
+  Ptr MetadataAsVal -> IO (Ptr Metadata)
+
+foreign import ccall unsafe "LLVMGetMDKindIDInContext" getMDKindIDInContext' ::
+  Ptr Context -> Ptr CChar -> CUInt -> IO MDKindID
+
+getMDKindIDInContext :: Ptr Context -> (Ptr CChar, CUInt) -> IO MDKindID
+getMDKindIDInContext ctx (c, n) = getMDKindIDInContext' ctx c n
+
+foreign import ccall unsafe "LLVM_Hs_GetMDKindNames" getMDKindNames ::
+  Ptr Context -> Ptr (Ptr CChar) -> Ptr CUInt -> CUInt -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetMDString" getMDString' ::
+  Ptr Context -> CString -> CUInt -> IO (Ptr MDString)
+
+getMDString :: Ptr Context -> (CString, CUInt) -> IO (Ptr MDString)
+getMDString ctx (p, n) = getMDString' ctx p n
+
+foreign import ccall unsafe "LLVM_Hs_MDValue" mdValue ::
+  Ptr Value -> IO (Ptr MDValue)
+
+foreign import ccall unsafe "LLVM_Hs_MetadataOperand" metadataOperand ::
+  Ptr Context -> Ptr Metadata -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVM_Hs_GetMDStringValue" getMDStringValue ::
+  Ptr MDString -> Ptr CUInt -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_Get_MDTuple" getMDTuple' ::
+  Ptr Context -> Ptr (Ptr Metadata) -> CUInt -> IO (Ptr MDTuple)
+
+getMDTuple :: Ptr Context -> (CUInt, Ptr (Ptr Metadata)) -> IO (Ptr MDTuple)
+getMDTuple ctx (n, vs) = getMDTuple' ctx vs n
+
+foreign import ccall unsafe "LLVM_Hs_CreateTemporaryMDNodeInContext" createTemporaryMDNodeInContext ::
+  Ptr Context -> IO (Ptr MDNode)
+
+foreign import ccall unsafe "LLVM_Hs_DestroyTemporaryMDNode" destroyTemporaryMDNode ::
+  Ptr MDNode -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_MDNode_GetNumOperands" getMDNodeNumOperands ::
+  Ptr MDNode -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_MDNode_GetOperand" getMDNodeOperand ::
+  Ptr MDNode -> CUInt -> IO (Ptr Metadata)
+
+foreign import ccall unsafe "LLVM_Hs_GetNamedMetadataName" getNamedMetadataName ::
+  Ptr NamedMetadata -> Ptr CUInt -> IO (Ptr CChar)
+
+foreign import ccall unsafe "LLVM_Hs_GetNamedMetadataNumOperands" getNamedMetadataNumOperands ::
+  Ptr NamedMetadata -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_GetNamedMetadataOperands" getNamedMetadataOperands ::
+  Ptr NamedMetadata -> Ptr (Ptr MDNode) -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_NamedMetadataAddOperands" namedMetadataAddOperands' ::
+  Ptr NamedMetadata -> Ptr (Ptr MDNode) -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_MetadataReplaceAllUsesWith" metadataReplaceAllUsesWith ::
+  Ptr MDNode -> Ptr Metadata -> IO ()
+
+namedMetadataAddOperands :: Ptr NamedMetadata -> (CUInt, Ptr (Ptr MDNode)) -> IO ()
+namedMetadataAddOperands nm (n, vs) = namedMetadataAddOperands' nm vs n
+
+-- DIEnumerator
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIEnumerator" getDIEnumerator ::
+  Ptr Context -> Int64 -> LLVMBool -> Ptr MDString -> IO (Ptr DIEnumerator)
+
+foreign import ccall unsafe "LLVM_Hs_DIEnumerator_GetValue" getDIEnumeratorValue ::
+  Ptr DIEnumerator -> IO Int64
+
+foreign import ccall unsafe "LLVM_Hs_DIEnumerator_GetIsUnsigned" getDIEnumeratorIsUnsigned ::
+  Ptr DIEnumerator -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DIEnumerator_GetName" getDIEnumeratorName ::
+  Ptr DIEnumerator -> IO (Ptr MDString)
+
+
+foreign import ccall unsafe "LLVM_Hs_DIFileGetFilename" getFileFilename ::
+  Ptr DIFile -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIFileGetDirectory" getFileDirectory ::
+  Ptr DIFile -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIFileGetChecksum" getFileChecksumValue ::
+  Ptr DIFile -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIFileGetChecksumKind" getFileChecksumKind ::
+  Ptr DIFile -> IO ChecksumKind
+
+foreign import ccall unsafe "LLVM_Hs_DIScope_GetName" getScopeName ::
+  Ptr DIScope -> Ptr CUInt -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetName" getTypeName ::
+  Ptr DIType -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetAlignInBits" getTypeAlignInBits ::
+  Ptr DIType -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetSizeInBits" getTypeSizeInBits ::
+  Ptr DIType -> IO Word64
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetOffsetInBits" getTypeOffsetInBits ::
+  Ptr DIType -> IO Word64
+
+foreign import ccall unsafe "LLVM_Hs_DINodeGetTag" getTag ::
+  Ptr DINode -> IO DwTag
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetLine" getTypeLine ::
+  Ptr DIType -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DITypeGetFlags" getTypeFlags ::
+  Ptr DIType -> IO DIFlags
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeType_GetElements" getElements ::
+  Ptr DICompositeType -> IO (Ptr MDTuple)
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeTypeGetVTableHolder" getVTableHolder ::
+  Ptr DICompositeType -> IO (Ptr DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeTypeGetBaseType" getCompositeBaseType ::
+  Ptr DICompositeType -> IO (Ptr DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeTypeGetRuntimeLang" getRuntimeLang ::
+  Ptr DICompositeType -> IO Word16
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeType_GetTemplateParameters" getTemplateParams ::
+  Ptr DICompositeType -> IO (TupleArray DITemplateParameter)
+
+foreign import ccall unsafe "LLVM_Hs_DICompositeTypeGetIdentifier" getIdentifier ::
+  Ptr DICompositeType -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIArrayType" getDIArrayType ::
+  Ptr Context -> TupleArray DISubrange -> Ptr DIType -> Word64 -> Word32 -> DIFlags -> IO (Ptr DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIEnumerationType" getDIEnumerationType ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> Ptr DIFile -> Word32 -> Word64 -> Word32 -> TupleArray DIEnumerator -> Ptr DIType -> Ptr MDString -> IO (Ptr DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIStructType" getDIStructType ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> Ptr DIFile ->
+  Word32 -> Word64 -> Word32 -> DIFlags ->
+  Ptr DIType -> TupleArray DIScope ->
+  Word16 -> Ptr DIType -> Ptr MDString ->
+  IO (Ptr DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIUnionType" getDIUnionType ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> Ptr DIFile ->
+  Word32 -> Word64 -> Word32 -> DIFlags ->
+  TupleArray DIScope ->
+  Word16 -> Ptr MDString ->
+  IO (Ptr DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIClassType" getDIClassType ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> Ptr DIFile ->
+  Word32 -> Word64 -> Word32 -> DIFlags ->
+  Ptr DIType -> TupleArray DIScope ->
+  Ptr DIType -> TupleArray DITemplateParameter -> Ptr MDString ->
+  IO (Ptr DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DINamespace" getDINamespace ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> LLVMBool -> IO (Ptr DINamespace)
+
+foreign import ccall unsafe "LLVM_Hs_DINamespace_GetExportSymbols" getNamespaceExportedSymbols ::
+  Ptr DINamespace -> IO LLVMBool
+
+-- DIScope
+
+foreign import ccall unsafe "LLVM_Hs_DIScope_GetScope" getScopeScope ::
+  Ptr DIScope -> IO (Ptr DIScope)
+
+foreign import ccall unsafe "LLVM_Hs_DIScope_GetFile" getScopeFile ::
+  Ptr DIScope -> IO (Ptr DIFile)
+
+-- DILexicalBlockBase
+foreign import ccall unsafe "LLVM_Hs_DILexicalBlockBaseGetScope" getLexicalBlockScope ::
+  Ptr DILexicalBlockBase -> IO (Ptr DILocalScope)
+
+-- DILexicalBlockFile
+foreign import ccall unsafe "LLVM_Hs_DILexicalBlockFileGetDiscriminator" getLexicalBlockFileDiscriminator ::
+  Ptr DILexicalBlockBase -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_Get_DILexicalBlockFile" getDILexicalBlockFile ::
+  Ptr Context -> Ptr DILocalScope -> Ptr DIFile -> Word32 -> IO (Ptr DILexicalBlockFile)
+
+-- DILexicalBlock
+foreign import ccall unsafe "LLVM_Hs_DILexicalBlockGetLine" getLexicalBlockLine ::
+  Ptr DILexicalBlockBase -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DILexicalBlockGetColumn" getLexicalBlockColumn ::
+  Ptr DILexicalBlockBase -> IO Word16
+
+foreign import ccall unsafe "LLVM_Hs_Get_DILexicalBlock" getDILexicalBlock ::
+  Ptr Context -> Ptr DILocalScope -> Ptr DIFile -> Word32 -> Word16 -> IO (Ptr DILexicalBlock)
+
+foreign import ccall unsafe "LLVM_Hs_DIDerivedTypeGetBaseType" getDerivedBaseType ::
+  Ptr DIType -> IO (Ptr DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DIDerivedTypeGetAddressSpace" getDerivedAddressSpace ::
+  Ptr DIType -> Ptr CUInt -> IO LLVMBool
+
+-- DISubroutineType
+
+foreign import ccall unsafe "LLVM_Hs_Get_DISubroutineType" getDISubroutineType ::
+  Ptr Context -> DIFlags -> Word8 -> TupleArray DIType -> IO (Ptr DISubroutineType)
+
+foreign import ccall unsafe "LLVM_Hs_DISubroutineType_GetCC" getSubroutineCC ::
+  Ptr DISubroutineType -> IO Word8
+
+foreign import ccall unsafe "LLVM_Hs_DISubroutine_GetTypeArray" getSubroutineTypeArray ::
+  Ptr DISubroutineType -> IO (TupleArray DIType)
+
+-- | DIBasicType
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIBasicType" getDIBasicType ::
+  Ptr Context -> DwTag -> Ptr MDString -> Word64 -> Word32 -> Encoding -> DIFlags -> IO (Ptr DIBasicType)
+
+foreign import ccall unsafe "LLVM_Hs_DIBasicType_GetEncoding" getBasicTypeEncoding ::
+  Ptr DIBasicType -> IO Encoding
+
+-- DIDerivedType
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIDerivedType" getDIDerivedType ::
+  Ptr Context ->
+  DwTag -> Ptr MDString -> Ptr DIFile -> CUInt -> Ptr DIScope ->
+  Ptr DIType -> Word64 -> Word32 -> Word64 -> Word32 -> LLVMBool -> DIFlags ->
+  IO (Ptr DIDerivedType)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIFile" getDIFile ::
+  Ptr Context -> Ptr MDString -> Ptr MDString -> ChecksumKind -> Ptr MDString -> IO (Ptr DIFile)
+
+-- DISubrange
+foreign import ccall unsafe "LLVM_Hs_Get_DISubrangeConstantCount" getDISubrangeConstantCount ::
+  Ptr Context -> Int64 -> Int64 -> IO (Ptr DISubrange)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DISubrangeVariableCount" getDISubrangeVariableCount ::
+  Ptr Context -> Ptr DIVariable -> Int64 -> IO (Ptr DISubrange)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DISubrangeVariableFields" getDISubrangeVariableFields ::
+  Ptr Context ->
+  Ptr Metadata -> -- count
+  Ptr Metadata -> -- lowerBound
+  Ptr Metadata -> -- upperBound
+  Ptr Metadata -> -- strides
+  IO (Ptr DISubrange)
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_HasConstantCount" getDISubrangeHasConstantCount ::
+  Ptr DISubrange -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetCount" getDISubrangeCount ::
+  Ptr DISubrange -> IO (Ptr Metadata)
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetCountVariable" getDISubrangeCountVariable ::
+  Ptr DISubrange -> IO (Ptr DIVariable)
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetCountConstant" getDISubrangeCountConstant ::
+  Ptr DISubrange -> IO Int64
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetLowerBound" getDISubrangeLowerBound ::
+  Ptr DISubrange -> IO (Ptr Metadata)
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetUpperBound" getDISubrangeUpperBound ::
+  Ptr DISubrange -> IO (Ptr Metadata)
+
+foreign import ccall unsafe "LLVM_Hs_DISubrange_GetStride" getDISubrangeStride ::
+  Ptr DISubrange -> IO (Ptr Metadata)
+
+-- DISubprogram
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetLine" getDISubprogramLine ::
+  Ptr DISubprogram -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetVirtuality" getDISubprogramVirtuality ::
+  Ptr DISubprogram -> IO DwVirtuality
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetVirtualIndex" getDISubprogramVirtualIndex ::
+  Ptr DISubprogram -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetScopeLine" getDISubprogramScopeLine ::
+  Ptr DISubprogram -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_IsOptimized" getDISubprogramIsOptimized ::
+  Ptr DISubprogram -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_IsDefinition" getDISubprogramIsDefinition ::
+  Ptr DISubprogram -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetLocalToUnit" getDISubprogramLocalToUnit ::
+  Ptr DISubprogram -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetThisAdjustment" getDISubprogramThisAdjustment ::
+  Ptr DISubprogram -> IO Int32
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetFlags" getDISubprogramFlags ::
+  Ptr DISubprogram -> IO DIFlags
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetLinkageName" getDISubprogramLinkageName ::
+  Ptr DISubprogram -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetType" getDISubprogramType ::
+  Ptr DISubprogram -> IO (Ptr DISubroutineType)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetContainingType" getDISubprogramContainingType ::
+  Ptr DISubprogram -> IO (Ptr DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetUnit" getDISubprogramUnit ::
+  Ptr DISubprogram -> IO (Ptr DICompileUnit)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetTemplateParams" getDISubprogramTemplateParams ::
+  Ptr DISubprogram -> IO (TupleArray DITemplateParameter)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetRetainedNodes" getDISubprogramRetainedNodes ::
+  Ptr DISubprogram -> IO (TupleArray DILocalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetThrownTypes" getDISubprogramThrownTypes ::
+  Ptr DISubprogram -> IO (TupleArray DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DISubprogram_GetDeclaration" getDISubprogramDeclaration ::
+  Ptr DISubprogram -> IO (Ptr DISubprogram)
+
+foreign import ccall unsafe "LLVM_Hs_Get_DISubprogram" getDISubprogram ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString ->
+  Ptr MDString -> Ptr DIFile -> CUInt ->
+  Ptr DISubroutineType -> LLVMBool -> LLVMBool -> CUInt ->
+  Ptr DIType -> DwVirtuality -> CUInt ->
+  Int32 -> DIFlags -> LLVMBool ->
+  Ptr DICompileUnit -> TupleArray DITemplateParameter -> Ptr DISubprogram ->
+  TupleArray DILocalVariable -> TupleArray DIType ->
+  IO (Ptr DISubprogram)
+
+-- DIExpression
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIExpression" getDIExpression' ::
+  Ptr Context -> CUInt -> Ptr Word64 -> IO (Ptr DIExpression)
+
+getDIExpression :: Ptr Context -> (CUInt, Ptr Word64) -> IO (Ptr DIExpression)
+getDIExpression ctx (numOps, ops) = getDIExpression' ctx numOps ops
+
+foreign import ccall unsafe "LLVM_Hs_DIExpression_GetNumElements" getDIExpressionNumElements ::
+  Ptr DIExpression -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DIExpression_GetElement" getDIExpressionElement ::
+  Ptr DIExpression -> CUInt -> IO Word64
+
+-- DIVariable
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetScope" getDIVariableScope ::
+  Ptr DIVariable -> IO (Ptr DIScope)
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetFile" getDIVariableFile ::
+  Ptr DIVariable -> IO (Ptr DIFile)
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetName" getDIVariableName ::
+  Ptr DIVariable -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetLine" getDIVariableLine ::
+  Ptr DIVariable -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetType" getDIVariableType ::
+  Ptr DIVariable -> IO (Ptr DIType)
+
+foreign import ccall unsafe "LLVM_Hs_DIVariable_GetAlignInBits" getDIVariableAlignInBits ::
+  Ptr DIVariable -> IO Word32
+
+-- DILocalVariable
+
+foreign import ccall unsafe "LLVM_Hs_Get_DILocalVariable" getDILocalVariable ::
+  Ptr Context ->
+  Ptr DIScope -> CString -> Ptr DIFile -> Word32 -> Ptr DIType -> Word16 -> DIFlags -> Word32 ->
+  IO (Ptr DILocalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_DILocalVariable_GetArg" getDILocalVariableArg ::
+  Ptr DILocalVariable -> IO Word16
+
+foreign import ccall unsafe "LLVM_Hs_DILocalVariable_GetFlags" getDILocalVariableFlags ::
+  Ptr DILocalVariable -> IO DIFlags
+
+-- DIGlobalVariable
+
+foreign import ccall unsafe "LLVM_Hs_Get_DIGlobalVariable" getDIGlobalVariable ::
+  Ptr Context ->
+  Ptr DIScope -> Ptr MDString -> Ptr MDString ->
+  Ptr DIFile -> CUInt -> Ptr DIType ->
+  LLVMBool -> LLVMBool ->
+  Ptr DIDerivedType ->
+  TupleArray DITemplateParameter ->
+  Word32 ->
+  IO (Ptr DIGlobalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariable_GetLocal" getDIGlobalVariableLocal ::
+  Ptr DIGlobalVariable -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariable_GetDefinition" getDIGlobalVariableDefinition ::
+  Ptr DIGlobalVariable -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariable_GetLinkageName" getDIGlobalVariableLinkageName ::
+  Ptr DIGlobalVariable -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariable_GetStaticDataMemberDeclaration" getDIGlobalVariableStaticDataMemberDeclaration ::
+  Ptr DIGlobalVariable -> IO (Ptr DIDerivedType)
+
+-- DICompileUnit
+
+foreign import ccall unsafe "LLVM_Hs_Get_DICompileUnit" getDICompileUnit ::
+  Ptr Context ->
+  CUInt -> Ptr DIFile -> Ptr MDString -> LLVMBool -> Ptr MDString ->
+  CUInt -> Ptr MDString -> DebugEmissionKind -> TupleArray DICompositeType -> TupleArray DIScope ->
+  TupleArray DIGlobalVariableExpression -> TupleArray DIImportedEntity -> TupleArray DIMacroNode ->
+  Word64 -> LLVMBool ->
+  LLVMBool -> DebugNameTableKind -> LLVMBool ->
+  IO (Ptr DICompileUnit)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetLanguage" getDICompileUnitLanguage ::
+  Ptr DICompileUnit -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetSplitDebugInlining" getDICompileUnitSplitDebugInlining ::
+  Ptr DICompileUnit -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetDebugInfoForProfiling" getDICompileUnitDebugInfoForProfiling ::
+  Ptr DICompileUnit -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetOptimized" getDICompileUnitOptimized ::
+  Ptr DICompileUnit -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetRuntimeVersion" getDICompileUnitRuntimeVersion ::
+  Ptr DICompileUnit -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetProducer" getDICompileUnitProducer ::
+  Ptr DICompileUnit -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetFlags" getDICompileUnitFlags ::
+  Ptr DICompileUnit -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetSplitDebugFilename" getDICompileUnitSplitDebugFilename ::
+  Ptr DICompileUnit -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetEmissionKind" getDICompileUnitEmissionKind ::
+  Ptr DICompileUnit -> IO DebugEmissionKind
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetNameTableKind" getDICompileUnitNameTableKind ::
+  Ptr DICompileUnit -> IO DebugNameTableKind
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetDWOId" getDICompileUnitDWOId ::
+  Ptr DICompileUnit -> IO Word64
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetEnumTypes" getDICompileUnitEnumTypes ::
+  Ptr DICompileUnit -> IO (TupleArray DICompositeType)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetRetainedTypes" getDICompileUnitRetainedTypes ::
+  Ptr DICompileUnit -> IO (TupleArray DIScope)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetGlobalVariables" getDICompileUnitGlobalVariables ::
+  Ptr DICompileUnit -> IO (TupleArray DIGlobalVariableExpression)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetImportedEntities" getDICompileUnitImportedEntities ::
+  Ptr DICompileUnit -> IO (TupleArray DIImportedEntity)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetMacros" getDICompileUnitMacros ::
+  Ptr DICompileUnit -> IO (TupleArray DIMacroNode)
+
+foreign import ccall unsafe "LLVM_Hs_DICompileUnit_GetRangesBaseAddress" getDICompileUnitRangesBaseAddress ::
+  Ptr DICompileUnit -> IO LLVMBool
+
+-- DIFlags
+foreign import ccall unsafe "LLVM_Hs_DIFlags_GetFlag" getDIFlag ::
+  CString -> IO DIFlags
+
+-- DITemplateParameter
+
+foreign import ccall unsafe "LLVM_Hs_DITemplateParameter_GetName" getDITemplateParameterName ::
+  Ptr DITemplateParameter -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DITemplateParameter_GetType" getDITemplateParameterType ::
+  Ptr DITemplateParameter -> IO (Ptr DIType)
+
+-- DITemplateTypeParameter
+
+foreign import ccall unsafe "LLVM_Hs_Get_DITemplateTypeParameter" getDITemplateTypeParameter ::
+  Ptr Context -> Ptr MDString -> Ptr DIType -> IO (Ptr DITemplateTypeParameter)
+
+-- DITemplateValueParameter
+
+foreign import ccall unsafe "LLVM_Hs_Get_DITemplateValueParameter" getDITemplateValueParameter ::
+  Ptr Context -> Ptr MDString -> Ptr DIType -> DwTag -> Bool -> Ptr Metadata -> IO (Ptr DITemplateValueParameter)
+
+foreign import ccall unsafe "LLVM_Hs_DITemplateValueParameter_GetValue" getDITemplateValueParameterValue ::
+  Ptr DITemplateValueParameter -> IO (Ptr Metadata)
+
+-- DIMacro
+foreign import ccall unsafe "LLVM_Hs_Get_DIMacro" getDIMacro ::
+  Ptr Context -> Macinfo -> Word32 -> Ptr MDString -> Ptr MDString -> IO (Ptr DIMacro)
+
+foreign import ccall unsafe "LLVM_Hs_DIMacro_GetMacinfo" getDIMacroMacinfo ::
+  Ptr DIMacro -> IO Macinfo
+
+foreign import ccall unsafe "LLVM_Hs_DIMacro_GetLine" getDIMacroLine ::
+  Ptr DIMacro -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DIMacro_GetName" getDIMacroName ::
+  Ptr DIMacro -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIMacro_GetValue" getDIMacroValue ::
+  Ptr DIMacro -> IO (Ptr MDString)
+
+-- DIMacroFile
+foreign import ccall unsafe "LLVM_Hs_Get_DIMacroFile" getDIMacroFile ::
+  Ptr Context -> Word32 -> Ptr DIFile -> TupleArray DIMacroNode -> IO (Ptr DIMacroFile)
+
+foreign import ccall unsafe "LLVM_Hs_DIMacroFile_GetLine" getDIMacroFileLine ::
+  Ptr DIMacroFile -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DIMacroFile_GetFile" getDIMacroFileFile ::
+  Ptr DIMacroFile -> IO (Ptr DIFile)
+
+foreign import ccall unsafe "LLVM_Hs_DIMacroFile_GetNumElements" getDIMacroFileNumElements ::
+  Ptr DIMacroFile -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_DIMacroFile_GetElement" getDIMacroFileElement ::
+  Ptr DIMacroFile -> CUInt -> IO (Ptr DIMacroNode)
+
+-- DIImportedEntity
+foreign import ccall unsafe "LLVM_Hs_Get_DIImportedEntity" getDIImportedEntity ::
+  Ptr Context -> DwTag -> Ptr DIScope -> Ptr DINode -> Ptr DIFile -> Word32 -> Ptr MDString -> IO (Ptr DIImportedEntity)
+
+foreign import ccall unsafe "LLVM_Hs_DIImportedEntity_GetLine" getDIImportedEntityLine ::
+  Ptr DIImportedEntity -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DIImportedEntity_GetScope" getDIImportedEntityScope ::
+  Ptr DIImportedEntity -> IO (Ptr DIScope)
+
+foreign import ccall unsafe "LLVM_Hs_DIImportedEntity_GetEntity" getDIImportedEntityEntity ::
+  Ptr DIImportedEntity -> IO (Ptr DINode)
+
+foreign import ccall unsafe "LLVM_Hs_DIImportedEntity_GetName" getDIImportedEntityName ::
+  Ptr DIImportedEntity -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIImportedEntity_GetFile" getDIImportedEntityFile ::
+  Ptr DIImportedEntity -> IO (Ptr DIFile)
+
+-- DIGlobalVariableExpression
+foreign import ccall unsafe "LLVM_Hs_Get_DIGlobalVariableExpression" getDIGlobalVariableExpression ::
+  Ptr Context -> Ptr DIGlobalVariable -> Ptr DIExpression -> IO (Ptr DIGlobalVariableExpression)
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariableExpression_GetVariable" getDIGlobalVariableExpressionVariable ::
+  Ptr DIGlobalVariableExpression -> IO (Ptr DIGlobalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_DIGlobalVariableExpression_GetExpression" getDIGlobalVariableExpressionExpression ::
+  Ptr DIGlobalVariableExpression -> IO (Ptr DIExpression)
+
+-- DIObjCProperty
+foreign import ccall unsafe "LLVM_Hs_Get_DIObjCProperty" getDIObjCProperty ::
+  Ptr Context -> Ptr MDString -> Ptr DIFile -> Word32 -> Ptr MDString -> Ptr MDString -> Word32 -> Ptr DIType -> IO (Ptr DIObjCProperty)
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetLine" getDIObjCPropertyLine ::
+  Ptr DIObjCProperty -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetAttributes" getDIObjCPropertyAttributes ::
+  Ptr DIObjCProperty -> IO Word32
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetName" getDIObjCPropertyName ::
+  Ptr DIObjCProperty -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetFile" getDIObjCPropertyFile ::
+  Ptr DIObjCProperty -> IO (Ptr DIFile)
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetGetterName" getDIObjCPropertyGetterName ::
+  Ptr DIObjCProperty -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetSetterName" getDIObjCPropertySetterName ::
+  Ptr DIObjCProperty -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIObjCProperty_GetType" getDIObjCPropertyType ::
+  Ptr DIObjCProperty -> IO (Ptr DIType)
+
+-- DIModule
+foreign import ccall unsafe "LLVM_Hs_Get_DIModule" getDIModule ::
+  Ptr Context -> Ptr DIScope -> Ptr MDString -> Ptr MDString -> Ptr MDString -> Ptr MDString -> Word32 -> IO (Ptr DIModule)
+
+foreign import ccall unsafe "LLVM_Hs_DIModule_GetConfigurationMacros" getDIModuleConfigurationMacros ::
+  Ptr DIModule -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIModule_GetIncludePath" getDIModuleIncludePath ::
+  Ptr DIModule -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIModule_GetAPINotesFile" getDIModuleAPINotesFile ::
+  Ptr DIModule -> IO (Ptr MDString)
+
+foreign import ccall unsafe "LLVM_Hs_DIModule_GetLineNo" getDIModuleLineNo ::
+  Ptr DIModule -> IO Word32
diff --git a/src/LLVM/Internal/FFI/MetadataC.cpp b/src/LLVM/Internal/FFI/MetadataC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/MetadataC.cpp
@@ -0,0 +1,937 @@
+#define __STDC_LIMIT_MACROS
+
+#include <iostream>
+#include "llvm/Support/FormattedStream.h"
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm-c/Core.h"
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMMetadataRef LLVM_Hs_IsAMDString(LLVMMetadataRef md) {
+    if (isa<MDString>(unwrap(md))) {
+        return md;
+    }
+    return nullptr;
+}
+
+const char *LLVM_Hs_GetMDStringValue(LLVMMetadataRef md, unsigned* len) {
+    if (const MDString *S = dyn_cast<MDString>(unwrap(md))) {
+      *len = S->getString().size();
+      return S->getString().data();
+    }
+    *len = 0;
+    return nullptr;
+}
+
+MDString* LLVM_Hs_GetMDString(LLVMContextRef c, const char* str, unsigned len) {
+    if (len == 0) {
+        return nullptr;
+    }
+    return MDString::get(*unwrap(c), StringRef(str, len));
+}
+
+LLVMMetadataRef LLVM_Hs_MDValue(LLVMValueRef v) {
+    return wrap(ValueAsMetadata::get(unwrap(v)));
+}
+
+LLVMValueRef LLVM_Hs_MetadataOperand(LLVMContextRef c, LLVMMetadataRef md) {
+    return wrap(MetadataAsValue::get(*unwrap(c), unwrap(md)));
+}
+
+LLVMMetadataRef LLVM_Hs_IsAMDNode(LLVMMetadataRef md) {
+    if (isa<MDNode>(unwrap(md))) {
+        return md;
+    }
+    return nullptr;
+}
+
+LLVMMetadataRef LLVM_Hs_IsAMDValue(LLVMMetadataRef md) {
+    if (isa<ValueAsMetadata>(unwrap(md))) {
+        return md;
+    }
+    return nullptr;
+}
+
+LLVMValueRef LLVM_Hs_GetMDValue(LLVMMetadataRef md) {
+    return wrap(unwrap<ValueAsMetadata>(md)->getValue());
+}
+
+LLVMValueRef LLVM_Hs_IsAMetadataOperand(LLVMValueRef val) {
+    if (isa<MetadataAsValue>(unwrap(val))) {
+        return val;
+    }
+    return nullptr;
+}
+
+LLVMMetadataRef LLVM_Hs_GetMetadataOperand(LLVMValueRef val) {
+    return wrap(unwrap<MetadataAsValue>(val)->getMetadata());
+}
+
+MDTuple* LLVM_Hs_Get_MDTuple(LLVMContextRef c,
+                                    LLVMMetadataRef *mds,
+                                    unsigned count) {
+    return MDTuple::get(*unwrap(c), {unwrap(mds), count});
+}
+
+/*
+void LLVM_Hs_DumpMetadata(LLVMMetadataRef md) {
+    unwrap(md)->dump();
+}
+*/
+
+unsigned LLVM_Hs_GetMDKindNames(
+	LLVMContextRef c,
+	const char **s,
+	unsigned *l,
+	unsigned n
+) {
+	SmallVector<StringRef, 8> ns;
+	unwrap(c)->getMDKindNames(ns);
+	if (ns.size() <= n) {
+		for(unsigned i=0; i < ns.size(); ++i) {
+			s[i] = ns[i].data();
+			l[i] = ns[i].size();
+		}
+	}
+	return ns.size();
+}
+
+unsigned LLVM_Hs_MDNode_GetNumOperands(MDNode* v) {
+	return v->getNumOperands();
+}
+
+Metadata* LLVM_Hs_MDNode_GetOperand(MDNode* v, unsigned i) {
+	return v->getOperand(i).get();
+}
+
+void LLVM_Hs_NamedMetadataAddOperands(
+	NamedMDNode *n,
+	LLVMMetadataRef *ops,
+	unsigned nOps
+) {
+	for(unsigned i = 0; i != nOps; ++i) n->addOperand(unwrap<MDNode>(ops[i]));
+}
+
+const char *LLVM_Hs_GetNamedMetadataName(
+	NamedMDNode *n,
+	unsigned *len
+) {
+	StringRef s = n->getName();
+	*len = s.size();
+	return s.data();
+}
+
+const char *LLVM_Hs_GetStringRef(
+    StringRef* s,
+    unsigned *len
+) {
+    *len = s->size();
+    return s->data();
+}
+
+unsigned LLVM_Hs_GetNamedMetadataNumOperands(NamedMDNode *n) {
+	return n->getNumOperands();
+}
+
+void LLVM_Hs_GetNamedMetadataOperands(NamedMDNode *n, LLVMMetadataRef *dest) {
+	for(unsigned i = 0; i != n->getNumOperands(); ++i)
+		dest[i] = wrap(n->getOperand(i));
+}
+
+LLVMMetadataRef LLVM_Hs_CreateTemporaryMDNodeInContext(LLVMContextRef c) {
+	return wrap(MDNode::getTemporary(*unwrap(c), ArrayRef<Metadata *>()).release());
+}
+
+void LLVM_Hs_DestroyTemporaryMDNode(LLVMMetadataRef v) {
+    MDNode::deleteTemporary(unwrap<MDNode>(v));
+}
+
+void LLVM_Hs_GetMDNodeOperands(LLVMMetadataRef md, LLVMMetadataRef *dest) {
+    const auto *N = cast<MDNode>(unwrap(md));
+    const unsigned numOperands = N->getNumOperands();
+    for (unsigned i = 0; i < numOperands; i++)
+        dest[i] = wrap(N->getOperand(i));
+}
+
+void LLVM_Hs_MetadataReplaceAllUsesWith(LLVMMetadataRef md, LLVMMetadataRef replacement) {
+    auto *Node = unwrap<MDNode>(md);
+    Node->replaceAllUsesWith(unwrap<Metadata>(replacement));
+    MDNode::deleteTemporary(Node);
+}
+
+// DILocation
+
+DILocation* LLVM_Hs_Get_DILocation(LLVMContextRef cxt, uint32_t line, uint16_t column, DILocalScope* scope) {
+    LLVMContext& c = *unwrap(cxt);
+
+    return DILocation::get(c, line, column, scope);
+}
+
+uint32_t LLVM_Hs_DILocation_GetLine(DILocation *md) {
+    return md->getLine();
+}
+
+uint16_t LLVM_Hs_DILocation_GetColumn(DILocation *md) {
+    return md->getColumn();
+}
+
+DILocalScope* LLVM_Hs_DILocation_GetScope(DILocation *md) {
+    return md->getScope();
+}
+
+unsigned LLVM_Hs_GetMetadataClassId(LLVMMetadataRef md) {
+    return (unwrap(md))->getMetadataID();
+}
+
+uint16_t LLVM_Hs_DINodeGetTag(DINode *md) {
+    return md->getTag();
+}
+
+DINode::DIFlags LLVM_Hs_DITypeGetFlags(DIType *md) {
+    return md->getFlags();
+}
+
+// DIEnumerator
+
+DIEnumerator* LLVM_Hs_Get_DIEnumerator(LLVMContextRef cxt, int64_t value, LLVMBool isUnsigned, MDString* name) {
+    LLVMContext& c = *unwrap(cxt);
+    return DIEnumerator::get(c, value, isUnsigned, name);
+}
+
+int64_t LLVM_Hs_DIEnumerator_GetValue(DIEnumerator* md) {
+    return md->getValue().getLimitedValue();
+}
+
+LLVMBool LLVM_Hs_DIEnumerator_GetIsUnsigned(DIEnumerator* md) {
+    return md->isUnsigned();
+}
+
+MDString* LLVM_Hs_DIEnumerator_GetName(DIEnumerator* md) {
+    return md->getRawName();
+}
+
+MDString* LLVM_Hs_DIFileGetFilename(DIFile *di) {
+    return di->getRawFilename();
+}
+
+MDString* LLVM_Hs_DIFileGetDirectory(DIFile *di) {
+    return di->getRawDirectory();
+}
+
+MDString* LLVM_Hs_DIFileGetChecksum(DIFile *di) {
+    auto checksumInfo = di->getRawChecksum();
+    if (checksumInfo.hasValue()) {
+        return checksumInfo->Value;
+    }
+    return nullptr;
+}
+
+llvm::DIFile::ChecksumKind LLVM_Hs_DIFileGetChecksumKind(DIFile *di) {
+    auto checksumInfo = di->getRawChecksum();
+    if (checksumInfo.hasValue()) {
+        return checksumInfo->Kind;
+    }
+    return static_cast<llvm::DIFile::ChecksumKind>(0);
+}
+
+// DIScope
+
+DIScope* LLVM_Hs_DIScope_GetScope(DIScope *ds) {
+    return cast_or_null<DIScope>(ds->getScope());
+}
+
+DIFile* LLVM_Hs_DIScope_GetFile(DIScope *ds) {
+    return ds->getFile();
+}
+
+const char* LLVM_Hs_DIScope_GetName(DIScope *ds, unsigned *len) {
+    StringRef s = ds->getName();
+    *len = s.size();
+    return s.data();
+}
+
+// DINamespace
+
+DINamespace* LLVM_Hs_Get_DINamespace(LLVMContextRef ctx, DIScope* scope, MDString* name, LLVMBool exportSymbols) {
+    return DINamespace::get(*unwrap(ctx), scope, name, exportSymbols);
+}
+
+LLVMBool LLVM_Hs_DINamespace_GetExportSymbols(DINamespace *ds) {
+    return ds->getExportSymbols();
+}
+
+MDString* LLVM_Hs_DITypeGetName(DIType *ds) {
+    return ds->getRawName();
+}
+
+uint64_t LLVM_Hs_DITypeGetSizeInBits(DIType *ds) {
+    return ds->getSizeInBits();
+}
+
+uint64_t LLVM_Hs_DITypeGetOffsetInBits(DIType *ds) {
+    return ds->getOffsetInBits();
+}
+
+uint32_t LLVM_Hs_DITypeGetAlignInBits(DIType *ds) {
+    return ds->getAlignInBits();
+}
+
+uint32_t LLVM_Hs_DITypeGetLine(DIType *ds) {
+    return ds->getLine();
+}
+
+// DIBasicType
+
+DIBasicType* LLVM_Hs_Get_DIBasicType(LLVMContextRef ctx, uint16_t tag, MDString *name, uint64_t sizeInBits, uint32_t alignInBits, unsigned encoding, DINode::DIFlags flags) {
+    return DIBasicType::get(*unwrap(ctx), tag, name, sizeInBits, alignInBits, encoding, flags);
+}
+
+
+unsigned LLVM_Hs_DIBasicType_GetEncoding(DIBasicType *ds) {
+    return ds->getEncoding();
+}
+
+// DIDerivedType
+DIDerivedType* LLVM_Hs_Get_DIDerivedType(LLVMContextRef ctx, uint16_t tag, MDString* name, DIFile *file, unsigned line, DIScope *scope, DIType *baseType, uint64_t sizeInBits, uint32_t alignInBits, uint64_t offsetInBits, uint32_t dwarfAddressSpace, LLVMBool dwarfAddressSpacePresent, DINode::DIFlags flags) {
+    LLVMContext& c = *unwrap(ctx);
+    Optional<unsigned> addrSpace;
+    if (dwarfAddressSpacePresent) {
+        addrSpace = dwarfAddressSpace;
+    }
+    return DIDerivedType::get(c, tag, name, file, line, scope, baseType, sizeInBits, alignInBits, offsetInBits, addrSpace, flags);
+}
+
+DIFile* LLVM_Hs_Get_DIFile(LLVMContextRef ctx, MDString* filename, MDString* directory, unsigned checksumKind, MDString* checksum) {
+    LLVMContext& c = *unwrap(ctx);
+    if (!checksum) {
+        return DIFile::get(c, filename, directory);
+    }
+    return DIFile::get(c, filename, directory, DIFile::ChecksumInfo<MDString*>(static_cast<llvm::DIFile::ChecksumKind>(checksumKind), checksum));
+}
+
+DISubrange* LLVM_Hs_Get_DISubrangeConstantCount(LLVMContextRef ctx, int64_t count, int64_t lowerBound) {
+    return DISubrange::get(*unwrap(ctx), count, lowerBound);
+}
+
+DISubrange* LLVM_Hs_Get_DISubrangeVariableCount(LLVMContextRef ctx, DIVariable* count, int64_t lowerBound) {
+    return DISubrange::get(*unwrap(ctx), count, lowerBound);
+}
+
+DISubrange* LLVM_Hs_Get_DISubrangeVariableFields(LLVMContextRef ctx, Metadata* count, Metadata* lowerBound, Metadata* upperBound, Metadata* stride) {
+    return DISubrange::get(*unwrap(ctx), count, lowerBound, upperBound, stride);
+}
+
+LLVMBool LLVM_Hs_DISubrange_HasConstantCount(DISubrange* range) {
+    return range->getCount().is<ConstantInt*>();
+}
+
+Metadata* LLVM_Hs_DISubrange_GetCount(DISubrange* range) {
+    return range->getRawCountNode();
+}
+
+int64_t LLVM_Hs_DISubrange_GetCountConstant(DISubrange* range) {
+    return range->getCount().dyn_cast<ConstantInt*>()->getSExtValue();
+}
+
+DIVariable* LLVM_Hs_DISubrange_GetCountVariable(DISubrange* range) {
+    return range->getCount().dyn_cast<DIVariable*>();
+}
+
+Metadata* LLVM_Hs_DISubrange_GetLowerBound(DISubrange* range) {
+    return range->getRawLowerBound();
+}
+
+Metadata* LLVM_Hs_DISubrange_GetUpperBound(DISubrange* range) {
+    return range->getRawUpperBound();
+}
+
+Metadata* LLVM_Hs_DISubrange_GetStride(DISubrange* range) {
+    return range->getRawStride();
+}
+
+LLVMMetadataRef LLVM_Hs_IsADIVariable(LLVMMetadataRef md) {
+    if (isa<DIVariable>(unwrap(md))) {
+        return md;
+    }
+    return nullptr;
+}
+
+LLVMMetadataRef LLVM_Hs_IsADIExpression(LLVMMetadataRef md) {
+    if (isa<DIExpression>(unwrap(md))) {
+        return md;
+    }
+    return nullptr;
+}
+
+MDTuple* LLVM_Hs_DICompositeType_GetElements(DICompositeType *dt) {
+    return cast_or_null<MDTuple>(dt->getRawElements());
+}
+
+DIType* LLVM_Hs_DICompositeTypeGetVTableHolder(DICompositeType *dt) {
+    return dt->getVTableHolder();
+}
+
+DIType* LLVM_Hs_DICompositeTypeGetBaseType(DICompositeType *dt) {
+    return dt->getBaseType();
+}
+
+DIType* LLVM_Hs_DIDerivedTypeGetBaseType(DIDerivedType *dt) {
+    return dt->getBaseType();
+}
+
+uint16_t LLVM_Hs_DICompositeTypeGetRuntimeLang(DICompositeType *dt) {
+    return dt->getRuntimeLang();
+}
+
+MDTuple* LLVM_Hs_DICompositeType_GetTemplateParameters(DICompositeType *dt) {
+    return cast_or_null<MDTuple>(dt->getRawTemplateParams());
+}
+
+MDString* LLVM_Hs_DICompositeTypeGetIdentifier(DICompositeType *dt) {
+    return dt->getRawIdentifier();
+}
+
+DICompositeType *LLVM_Hs_Get_DIArrayType(LLVMContextRef ctx, MDTuple* subscripts, DIType* elTy, uint64_t size, uint32_t align, DINode::DIFlags flags) {
+    return DICompositeType::get(*unwrap(ctx), dwarf::DW_TAG_array_type, "", nullptr, 0, nullptr, elTy, size, align, 0, flags, subscripts, 0, nullptr);
+}
+
+DICompositeType* LLVM_Hs_Get_DIEnumerationType(LLVMContextRef ctx, DIScope* scope, MDString* name, DIFile *file, uint32_t line, uint64_t size, uint32_t align, MDTuple* elements, DIType* underlyingType, MDString* uniqueIdentifier) {
+    return DICompositeType::get(*unwrap(ctx), dwarf::DW_TAG_enumeration_type, name, file, line, scope, underlyingType, size, align, 0, DINode::FlagZero, elements, 0, nullptr, nullptr, uniqueIdentifier);
+}
+
+DICompositeType *LLVM_Hs_Get_DIStructType(
+    LLVMContextRef ctx, DIScope *scope, MDString *name, DIFile *file,
+    uint32_t line, uint64_t size, uint32_t align, DINode::DIFlags flags,
+    DIType *derivedFrom, MDTuple *elements,
+    uint16_t runtimeLang, DIType *vtableHolder, MDString *uniqueIdentifier) {
+    return DICompositeType::get(*unwrap(ctx), dwarf::DW_TAG_structure_type, name, file,
+                                line, scope, derivedFrom, size, align, 0, flags,
+                                elements, runtimeLang, vtableHolder, nullptr,
+                                uniqueIdentifier);
+}
+
+DICompositeType *LLVM_Hs_Get_DIUnionType(
+    LLVMContextRef ctx, DIScope *scope, MDString *name, DIFile *file,
+    uint32_t line, uint64_t size, uint32_t align, DINode::DIFlags flags,
+    MDTuple *elements,
+    uint16_t runtimeLang, MDString *uniqueIdentifier) {
+    return DICompositeType::get(*unwrap(ctx), dwarf::DW_TAG_union_type, name, file,
+                                line, scope, nullptr, size, align, 0, flags,
+                                elements, runtimeLang, nullptr, nullptr,
+                                uniqueIdentifier);
+}
+
+DICompositeType *LLVM_Hs_Get_DIClassType(
+    LLVMContextRef ctx, DIScope *scope, MDString *name, DIFile *file,
+    uint32_t line, uint64_t size, uint32_t align, DINode::DIFlags flags,
+    DIType *derivedFrom, MDTuple *elements,
+    DIType *vtableHolder, MDTuple* templateParams, MDString *uniqueIdentifier) {
+    return DICompositeType::get(*unwrap(ctx), dwarf::DW_TAG_class_type, name, file,
+                                line, scope, derivedFrom, size, align, 0, flags,
+                                elements, 0, vtableHolder, templateParams,
+                                uniqueIdentifier);
+}
+
+
+// DILexicalBlockBase
+
+DILocalScope* LLVM_Hs_DILexicalBlockBaseGetScope(DILexicalBlockBase* bb) {
+    return bb->getScope();
+}
+
+// DILexicalBlockFile
+
+uint32_t LLVM_Hs_DILexicalBlockFileGetDiscriminator(DILexicalBlockFile* bf) {
+    return bf->getDiscriminator();
+}
+
+DILexicalBlockFile* LLVM_Hs_Get_DILexicalBlockFile(LLVMContextRef ctx, DILocalScope* scope, DIFile* file, uint32_t discriminator) {
+    return DILexicalBlockFile::get(*unwrap(ctx), scope, file, discriminator);
+}
+
+// DILexicalBlock
+
+uint32_t LLVM_Hs_DILexicalBlockGetLine(DILexicalBlock* lb) {
+    return lb->getLine();
+}
+
+uint16_t LLVM_Hs_DILexicalBlockGetColumn(DILexicalBlock* lb) {
+    return lb->getColumn();
+}
+
+DILexicalBlock* LLVM_Hs_Get_DILexicalBlock(LLVMContextRef ctx, DILocalScope* scope, DIFile *file, uint32_t line, uint16_t column) {
+    return DILexicalBlock::get(*unwrap(ctx), scope, file, line, column);
+}
+
+LLVMBool LLVM_Hs_DIDerivedTypeGetAddressSpace(DIDerivedType *a, unsigned *x) {
+    auto addressSpace = a->getDWARFAddressSpace();
+    if (addressSpace.hasValue()) {
+        *x = addressSpace.getValue();
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+// DISubroutineType
+
+DISubroutineType* LLVM_Hs_Get_DISubroutineType(LLVMContextRef ctx, DINode::DIFlags flags, uint8_t cc, MDTuple* types) {
+    return DISubroutineType::get(*unwrap(ctx), flags, cc, types);
+}
+
+uint8_t LLVM_Hs_DISubroutineType_GetCC(DISubroutineType *a) {
+    return a->getCC();
+}
+
+MDTuple* LLVM_Hs_DISubroutine_GetTypeArray(DISubroutineType *md) {
+    return cast_or_null<MDTuple>(md->getRawTypeArray());
+}
+
+// DISubprogram
+
+unsigned LLVM_Hs_DISubprogram_GetLine(DISubprogram* p) {
+    return p->getLine();
+}
+
+uint8_t LLVM_Hs_DISubprogram_GetVirtuality(DISubprogram* p) {
+    return p->getVirtuality();
+}
+
+unsigned LLVM_Hs_DISubprogram_GetVirtualIndex(DISubprogram* p) {
+    return p->getVirtualIndex();
+}
+
+unsigned LLVM_Hs_DISubprogram_GetScopeLine(DISubprogram* p) {
+    return p->getScopeLine();
+}
+
+LLVMBool LLVM_Hs_DISubprogram_IsOptimized(DISubprogram* p) {
+    return p->isOptimized();
+}
+
+LLVMBool LLVM_Hs_DISubprogram_IsDefinition(DISubprogram* p) {
+    return p->isDefinition();
+}
+
+LLVMBool LLVM_Hs_DISubprogram_GetLocalToUnit(DISubprogram* p) {
+    return p->isLocalToUnit();
+}
+
+int32_t LLVM_Hs_DISubprogram_GetThisAdjustment(DISubprogram* p) {
+    return p->getThisAdjustment();
+}
+
+DINode::DIFlags LLVM_Hs_DISubprogram_GetFlags(DISubprogram* p) {
+    return p->getFlags();
+}
+
+MDString* LLVM_Hs_DISubprogram_GetLinkageName(DISubprogram* p) {
+    return p->getRawLinkageName();
+}
+
+DISubroutineType* LLVM_Hs_DISubprogram_GetType(DISubprogram* p) {
+    return p->getType();
+}
+
+DIType* LLVM_Hs_DISubprogram_GetContainingType(DISubprogram* p) {
+    return p->getContainingType();
+}
+
+DICompileUnit* LLVM_Hs_DISubprogram_GetUnit(DISubprogram* p) {
+    return p->getUnit();
+}
+
+MDTuple* LLVM_Hs_DISubprogram_GetTemplateParams(DISubprogram* p) {
+    return cast_or_null<MDTuple>(p->getRawTemplateParams());
+}
+
+MDTuple* LLVM_Hs_DISubprogram_GetRetainedNodes(DISubprogram* p) {
+    return cast_or_null<MDTuple>(p->getRawRetainedNodes());
+}
+
+MDTuple* LLVM_Hs_DISubprogram_GetThrownTypes(DISubprogram* p) {
+    return cast_or_null<MDTuple>(p->getRawThrownTypes());
+}
+
+DISubprogram* LLVM_Hs_DISubprogram_GetDeclaration(DISubprogram* p) {
+    return p->getDeclaration();
+}
+
+DISubprogram *LLVM_Hs_Get_DISubprogram(
+    LLVMContextRef ctx, DIScope *scope, MDString *name,
+    MDString *linkageName, DIFile *file, unsigned line,
+    DISubroutineType *type, LLVMBool isLocal, LLVMBool isDefinition, unsigned scopeLine,
+    DIType *containingType, uint8_t virtuality, unsigned virtualIndex,
+    int32_t thisAdjustment, DINode::DIFlags flags, LLVMBool isOptimized,
+    DICompileUnit *unit, Metadata *templateParams, DISubprogram *declaration,
+    Metadata *variables, Metadata *thrownTypes) {
+    LLVMContext &c = *unwrap(ctx);
+    DISubprogram::DISPFlags spFlags = DISubprogram::toSPFlags(isLocal, isDefinition, isOptimized, virtuality);
+    if (isDefinition) {
+        return DISubprogram::getDistinct(
+          c, scope, name, linkageName, file,
+          line, type, scopeLine, containingType,
+          virtualIndex, thisAdjustment, flags, spFlags, unit,
+          templateParams, declaration, variables, thrownTypes);
+    } else {
+        return DISubprogram::get(
+          c, scope, name, linkageName, file,
+          line, type, scopeLine, containingType,
+          virtualIndex, thisAdjustment, flags, spFlags, unit,
+          templateParams, declaration, variables, thrownTypes);
+    }
+}
+
+// DIExpression
+
+DIExpression* LLVM_Hs_Get_DIExpression(LLVMContextRef ctx, unsigned numOps, uint64_t* ops) {
+    return DIExpression::get(*unwrap(ctx), {ops, numOps});
+}
+
+unsigned LLVM_Hs_DIExpression_GetNumElements(DIExpression* e) {
+    return e->getNumElements();
+}
+
+uint64_t LLVM_Hs_DIExpression_GetElement(DIExpression* e, unsigned i) {
+    return e->getElement(i);
+}
+
+// DIVariable
+
+DIScope* LLVM_Hs_DIVariable_GetScope(DIVariable* v) {
+    return v->getScope();
+}
+
+DIFile* LLVM_Hs_DIVariable_GetFile(DIVariable* v) {
+    return v->getFile();
+}
+
+MDString* LLVM_Hs_DIVariable_GetName(DIVariable* v) {
+    return v->getRawName();
+}
+
+unsigned LLVM_Hs_DIVariable_GetLine(DIVariable* v) {
+    return v->getLine();
+}
+
+DIType* LLVM_Hs_DIVariable_GetType(DIVariable* v) {
+    return v->getType();
+}
+
+uint32_t LLVM_Hs_DIVariable_GetAlignInBits(DIVariable* v) {
+    return v->getAlignInBits();
+}
+
+// DILocalVariable
+
+DILocalVariable* LLVM_Hs_Get_DILocalVariable(LLVMContextRef ctx,
+                                             DIScope* scope, MDString* name, DIFile* file,
+                                             uint32_t line, DIType* type, uint16_t arg,
+                                             DINode::DIFlags flags, uint32_t alignInBits) {
+    LLVMContext &c = *unwrap(ctx);
+    return DILocalVariable::get(c, static_cast<DILocalScope*>(scope), name, file, line, type,
+                                arg, flags, alignInBits);
+}
+
+uint16_t LLVM_Hs_DILocalVariable_GetArg(DILocalVariable* v) {
+    return v->getArg();
+}
+
+DINode::DIFlags LLVM_Hs_DILocalVariable_GetFlags(DILocalVariable* v) {
+    return v->getFlags();
+}
+
+// DIGlobalVariable
+
+DIGlobalVariable* LLVM_Hs_Get_DIGlobalVariable(LLVMContextRef ctx,
+                                               DIScope* scope, MDString* name, MDString* linkageName,
+                                               DIFile* file, unsigned line, DIType* type,
+                                               LLVMBool isLocalToUnit, LLVMBool isDefinition,
+                                               DIDerivedType* declaration,
+                                               Metadata* templateParams,
+                                               uint32_t alignInBits) {
+    LLVMContext &c = *unwrap(ctx);
+    return DIGlobalVariable::get(c, scope, name, linkageName,
+                                 file, line, type,
+                                 isLocalToUnit, isDefinition,
+                                 declaration, templateParams,
+                                 alignInBits);
+}
+
+LLVMBool LLVM_Hs_DIGlobalVariable_GetLocal(DIGlobalVariable* v) {
+    return v->isLocalToUnit();
+}
+
+LLVMBool LLVM_Hs_DIGlobalVariable_GetDefinition(DIGlobalVariable* v) {
+    return v->isDefinition();
+}
+
+MDString* LLVM_Hs_DIGlobalVariable_GetLinkageName(DIGlobalVariable* v) {
+    return v->getRawLinkageName();
+}
+
+DIDerivedType* LLVM_Hs_DIGlobalVariable_GetStaticDataMemberDeclaration(DIGlobalVariable* v) {
+    return v->getStaticDataMemberDeclaration();
+}
+
+// DICompileUnit
+DICompileUnit* LLVM_Hs_Get_DICompileUnit
+  (LLVMContextRef ctx,
+   unsigned sourceLanguage, DIFile* file, MDString* producer, LLVMBool isOptimized, MDString* flags,
+   unsigned runtimeVersion, MDString* splitDebugFilename, unsigned emissionKind, Metadata* enumTypes, Metadata* retainedTypes,
+   Metadata* globalVariables, Metadata* importedEntities, Metadata* macros, uint64_t dwoid, LLVMBool splitDebugInlining,
+   LLVMBool debugInfoForProfiling, unsigned nameTableKind, LLVMBool debugBaseAddress, MDString *sysRoot, MDString *sdk) {
+    LLVMContext &c = *unwrap(ctx);
+    return DICompileUnit::getDistinct
+        (c,
+         sourceLanguage, file, producer, isOptimized, flags,
+         runtimeVersion, splitDebugFilename, emissionKind, enumTypes, retainedTypes,
+         globalVariables, importedEntities, macros, dwoid, splitDebugInlining,
+         debugInfoForProfiling, nameTableKind, debugBaseAddress, sysRoot, sdk);
+}
+
+unsigned LLVM_Hs_DICompileUnit_GetLanguage(DICompileUnit* cu) {
+    return cu->getSourceLanguage();
+}
+
+LLVMBool LLVM_Hs_DICompileUnit_GetSplitDebugInlining(DICompileUnit* cu) {
+    return cu->getSplitDebugInlining();
+}
+
+LLVMBool LLVM_Hs_DICompileUnit_GetDebugInfoForProfiling(DICompileUnit* cu) {
+    return cu->getDebugInfoForProfiling();
+}
+
+LLVMBool LLVM_Hs_DICompileUnit_GetOptimized(DICompileUnit* cu) {
+    return cu->isOptimized();
+}
+
+unsigned LLVM_Hs_DICompileUnit_GetRuntimeVersion(DICompileUnit* cu) {
+    return cu->getRuntimeVersion();
+}
+
+MDString* LLVM_Hs_DICompileUnit_GetProducer(DICompileUnit* cu) {
+    return cu->getRawProducer();
+}
+
+MDString* LLVM_Hs_DICompileUnit_GetFlags(DICompileUnit* cu) {
+    return cu->getRawFlags();
+}
+
+MDString* LLVM_Hs_DICompileUnit_GetSplitDebugFilename(DICompileUnit* cu) {
+    return cu->getRawSplitDebugFilename();
+}
+
+unsigned LLVM_Hs_DICompileUnit_GetEmissionKind(DICompileUnit* cu) {
+    return cu->getEmissionKind();
+}
+
+unsigned LLVM_Hs_DICompileUnit_GetNameTableKind(DICompileUnit* cu) {
+    return static_cast<unsigned>(cu->getNameTableKind());
+}
+
+uint64_t LLVM_Hs_DICompileUnit_GetDWOId(DICompileUnit* cu) {
+    return cu->getDWOId();
+}
+
+MDTuple* LLVM_Hs_DICompileUnit_GetEnumTypes(DICompileUnit* cu) {
+    return cast_or_null<MDTuple>(cu->getRawEnumTypes());
+}
+
+MDTuple* LLVM_Hs_DICompileUnit_GetRetainedTypes(DICompileUnit* cu) {
+    return cast_or_null<MDTuple>(cu->getRawRetainedTypes());
+}
+
+MDTuple* LLVM_Hs_DICompileUnit_GetGlobalVariables(DICompileUnit* cu) {
+    return cast_or_null<MDTuple>(cu->getRawGlobalVariables());
+}
+
+MDTuple* LLVM_Hs_DICompileUnit_GetImportedEntities(DICompileUnit* cu) {
+    return cast_or_null<MDTuple>(cu->getRawImportedEntities());
+}
+
+MDTuple* LLVM_Hs_DICompileUnit_GetMacros(DICompileUnit* cu) {
+    return cast_or_null<MDTuple>(cu->getRawMacros());
+}
+
+LLVMBool LLVM_Hs_DICompileUnit_GetRangesBaseAddress(DICompileUnit* cu) {
+    return cu->getRangesBaseAddress();
+}
+
+// DIFlags
+
+// This is mainly intended for testing purposes
+DINode::DIFlags LLVM_Hs_DIFlags_GetFlag(const char* flag) {
+    return DINode::getFlag(flag);
+}
+
+// DITemplateParameter
+
+MDString* LLVM_Hs_DITemplateParameter_GetName(DITemplateParameter* p) {
+    return p->getRawName();
+}
+
+DIType* LLVM_Hs_DITemplateParameter_GetType(DITemplateParameter* p) {
+    return p->getType();
+}
+
+// DITemplateTypeParameter
+
+DITemplateTypeParameter* LLVM_Hs_Get_DITemplateTypeParameter(LLVMContextRef ctx, MDString* name, DIType* type, bool isDefault) {
+    return DITemplateTypeParameter::get(*unwrap(ctx), name, type, isDefault);
+}
+
+// DITemplateValueParameter
+
+DITemplateValueParameter* LLVM_Hs_Get_DITemplateValueParameter(LLVMContextRef ctx, MDString* name, DIType* type, uint16_t tag, bool isDefault, Metadata* value) {
+    return DITemplateValueParameter::get(*unwrap(ctx), tag, name, type, isDefault, value);
+}
+
+Metadata* LLVM_Hs_DITemplateValueParameter_GetValue(DITemplateValueParameter* p) {
+    return p->getValue();
+}
+
+// DIMacro
+DIMacro* LLVM_Hs_Get_DIMacro(LLVMContextRef ctx, unsigned macinfo, uint32_t line, MDString* name, MDString* value) {
+    return DIMacro::get(*unwrap(ctx), macinfo, line, name, value);
+}
+
+unsigned LLVM_Hs_DIMacro_GetMacinfo(DIMacro* m) {
+    return m->getMacinfoType();
+}
+
+uint32_t LLVM_Hs_DIMacro_GetLine(DIMacro* m) {
+    return m->getLine();
+}
+
+MDString* LLVM_Hs_DIMacro_GetName(DIMacro* m) {
+    return m->getRawName();
+}
+
+MDString* LLVM_Hs_DIMacro_GetValue(DIMacro* m) {
+    return m->getRawValue();
+}
+
+// DIMacroFile
+DIMacroFile* LLVM_Hs_Get_DIMacroFile(LLVMContextRef ctx, uint32_t line, DIFile* file, MDTuple* elems) {
+    return DIMacroFile::get(*unwrap(ctx), dwarf::DW_MACINFO_start_file, line, file, static_cast<Metadata*>(elems));
+}
+
+uint32_t LLVM_Hs_DIMacroFile_GetLine(DIMacroFile* m) {
+    return m->getLine();
+}
+
+DIFile* LLVM_Hs_DIMacroFile_GetFile(DIMacroFile* m) {
+    return m->getFile();
+}
+
+unsigned LLVM_Hs_DIMacroFile_GetNumElements(DIMacroFile* m) {
+    return m->getElements().size();
+}
+
+DIMacroNode* LLVM_Hs_DIMacroFile_GetElement(DIMacroFile* m, unsigned i) {
+    return m->getElements()[i];
+}
+
+// DIImportedEntity
+
+DIImportedEntity* LLVM_Hs_Get_DIImportedEntity(LLVMContextRef ctx, uint16_t tag, DIScope* scope, DINode* entity, DIFile* file, uint32_t line, MDString* name) {
+    return DIImportedEntity::get(*unwrap(ctx), tag, scope, entity, file, line, name);
+}
+
+uint32_t LLVM_Hs_DIImportedEntity_GetLine(DIImportedEntity* e) {
+    return e->getLine();
+}
+
+DIScope* LLVM_Hs_DIImportedEntity_GetScope(DIImportedEntity* e) {
+    return e->getScope();
+}
+
+DINode* LLVM_Hs_DIImportedEntity_GetEntity(DIImportedEntity* e) {
+    return e->getEntity();
+}
+
+MDString* LLVM_Hs_DIImportedEntity_GetName(DIImportedEntity* e) {
+    return e->getRawName();
+}
+
+DIFile* LLVM_Hs_DIImportedEntity_GetFile(DIImportedEntity* e) {
+    return e->getFile();
+}
+
+// DIGlobalVariableExpression
+
+DIGlobalVariableExpression* LLVM_Hs_Get_DIGlobalVariableExpression(LLVMContextRef ctx, DIGlobalVariable* var, DIExpression* expr) {
+    return DIGlobalVariableExpression::get(*unwrap(ctx), var, expr);
+}
+
+DIGlobalVariable* LLVM_Hs_DIGlobalVariableExpression_GetVariable(DIGlobalVariableExpression* e) {
+    return e->getVariable();
+}
+
+DIExpression* LLVM_Hs_DIGlobalVariableExpression_GetExpression(DIGlobalVariableExpression* e) {
+    return e->getExpression();
+}
+
+// DIObjCProperty
+
+DIObjCProperty* LLVM_Hs_Get_DIObjCProperty(LLVMContextRef ctx, MDString* name, DIFile* file, uint32_t line, MDString* getterName, MDString* setterName, uint32_t attributes, DIType* type) {
+    return DIObjCProperty::get(*unwrap(ctx), name, file, line, getterName, setterName, attributes, type);
+}
+
+uint32_t LLVM_Hs_DIObjCProperty_GetLine(DIObjCProperty* o) {
+    return o->getLine();
+}
+
+uint32_t LLVM_Hs_DIObjCProperty_GetAttributes(DIObjCProperty* o) {
+    return o->getAttributes();
+}
+
+MDString* LLVM_Hs_DIObjCProperty_GetName(DIObjCProperty* o) {
+    return o->getRawName();
+}
+
+DIFile* LLVM_Hs_DIObjCProperty_GetFile(DIObjCProperty* o) {
+    return o->getFile();
+}
+
+MDString* LLVM_Hs_DIObjCProperty_GetGetterName(DIObjCProperty* o) {
+    return o->getRawGetterName();
+}
+
+MDString* LLVM_Hs_DIObjCProperty_GetSetterName(DIObjCProperty* o) {
+    return o->getRawSetterName();
+}
+
+DIType* LLVM_Hs_DIObjCProperty_GetType(DIObjCProperty* o) {
+    return o->getType();
+}
+
+// DIModule
+
+DIModule* LLVM_Hs_Get_DIModule(LLVMContextRef ctx, DIFile* file, DIScope* scope, MDString* name, MDString* configurationMacros, MDString* includePath, MDString* apiNotesFile, unsigned lineNo) {
+    return DIModule::get(*unwrap(ctx), file, scope, name, configurationMacros, includePath, apiNotesFile, lineNo);
+}
+
+MDString* LLVM_Hs_DIModule_GetConfigurationMacros(DIModule* m) {
+    return m->getRawConfigurationMacros();
+}
+
+MDString* LLVM_Hs_DIModule_GetIncludePath(DIModule* m) {
+    return m->getRawIncludePath();
+}
+
+MDString* LLVM_Hs_DIModule_GetAPINotesFile(DIModule* m) {
+    return m->getRawAPINotesFile();
+}
+
+uint32_t LLVM_Hs_DIModule_GetLineNo(DIModule* m) {
+    return m->getLineNo();
+}
+}
diff --git a/src/LLVM/Internal/FFI/Module.hs b/src/LLVM/Internal/FFI/Module.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Module.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.Module where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.GlobalValue (COMDAT)
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.Type
+
+data Module
+
+foreign import ccall unsafe "LLVMModuleCreateWithNameInContext" moduleCreateWithNameInContext ::
+  CString -> Ptr Context -> IO (Ptr Module)
+
+foreign import ccall unsafe "LLVMGetModuleContext" getModuleContext ::
+  Ptr Module -> IO (Ptr Context)
+
+foreign import ccall unsafe "LLVMDisposeModule" disposeModule ::
+  Ptr Module -> IO ()
+
+foreign import ccall unsafe "LLVMGetDataLayout" getDataLayout ::
+  Ptr Module -> IO CString
+
+foreign import ccall unsafe "LLVMSetDataLayout" setDataLayout ::
+  Ptr Module -> CString -> IO ()
+
+foreign import ccall unsafe "LLVMGetTarget" getTargetTriple ::
+  Ptr Module -> IO CString
+
+foreign import ccall unsafe "LLVMSetTarget" setTargetTriple ::
+  Ptr Module -> CString -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetModuleIdentifier" getModuleIdentifier ::
+  Ptr Module -> IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_GetSourceFileName" getSourceFileName ::
+  Ptr Module -> IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_SetSourceFileName" setSourceFileName ::
+  Ptr Module -> Ptr CChar -> IO ()
+
+foreign import ccall unsafe "LLVMGetFirstGlobal" getFirstGlobal ::
+  Ptr Module -> IO (Ptr GlobalVariable)
+
+foreign import ccall unsafe "LLVMGetNextGlobal" getNextGlobal ::
+  Ptr GlobalVariable -> IO (Ptr GlobalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_GetFirstAlias" getFirstAlias ::
+  Ptr Module -> IO (Ptr GlobalAlias)
+
+foreign import ccall unsafe "LLVM_Hs_GetNextAlias" getNextAlias ::
+  Ptr GlobalAlias -> IO (Ptr GlobalAlias)
+
+foreign import ccall unsafe "LLVM_Hs_GetOrInsertCOMDAT" getOrInsertCOMDAT ::
+  Ptr Module -> CString -> IO (Ptr COMDAT)
+
+foreign import ccall unsafe "LLVMGetFirstFunction" getFirstFunction ::
+  Ptr Module -> IO (Ptr Function)
+
+foreign import ccall unsafe "LLVMGetNextFunction" getNextFunction ::
+  Ptr Function -> IO (Ptr Function)
+
+foreign import ccall unsafe "LLVM_Hs_GetFirstNamedMetadata" getFirstNamedMetadata ::
+  Ptr Module -> IO (Ptr NamedMetadata)
+
+foreign import ccall unsafe "LLVM_Hs_GetNextNamedMetadata" getNextNamedMetadata ::
+  Ptr NamedMetadata -> IO (Ptr NamedMetadata)
+
+foreign import ccall unsafe "LLVMAddGlobalInAddressSpace" addGlobalInAddressSpace ::
+  Ptr Module -> Ptr Type -> CString -> CUInt -> IO (Ptr GlobalVariable)
+
+foreign import ccall unsafe "LLVM_Hs_JustAddAlias" justAddAlias ::
+  Ptr Module -> Ptr Type -> AddrSpace -> CString -> IO (Ptr GlobalAlias)
+
+foreign import ccall unsafe "LLVMAddFunction" addFunction ::
+  Ptr Module -> CString -> Ptr Type -> IO (Ptr Function)
+
+foreign import ccall unsafe "LLVMGetNamedFunction" getNamedFunction ::
+  Ptr Module -> CString -> IO (Ptr Function)
+
+foreign import ccall unsafe "LLVM_Hs_GetOrAddNamedMetadata" getOrAddNamedMetadata ::
+  Ptr Module -> CString -> IO (Ptr NamedMetadata)
+
+foreign import ccall unsafe "LLVM_Hs_ModuleAppendInlineAsm" moduleAppendInlineAsm' ::
+  Ptr Module -> Ptr CChar -> CUInt -> IO ()
+
+newtype ModuleAsm a = ModuleAsm a
+
+moduleAppendInlineAsm :: Ptr Module -> ModuleAsm (Ptr CChar, CUInt) -> IO ()
+moduleAppendInlineAsm m (ModuleAsm (c, n)) = moduleAppendInlineAsm' m c n
+
+foreign import ccall unsafe "LLVM_Hs_ModuleGetInlineAsm" moduleGetInlineAsm ::
+  Ptr Module -> IO (ModuleAsm CString)
+
+foreign import ccall unsafe "LLVMLinkModules2" linkModules ::
+  Ptr Module -> Ptr Module -> IO LLVMBool
diff --git a/src/LLVM/Internal/FFI/ModuleC.cpp b/src/LLVM/Internal/FFI/ModuleC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ModuleC.cpp
@@ -0,0 +1,70 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/Module.h"
+#include "llvm-c/Core.h"
+
+using namespace llvm;
+
+extern "C" {
+
+char *LLVM_Hs_GetModuleIdentifier(LLVMModuleRef val) {
+	return strdup(unwrap(val)->getModuleIdentifier().c_str());
+}
+
+char *LLVM_Hs_GetSourceFileName(LLVMModuleRef val) {
+	return strdup(unwrap(val)->getSourceFileName().c_str());
+}
+
+void LLVM_Hs_SetSourceFileName(LLVMModuleRef val, const char* sourceFileName) {
+	return unwrap(val)->setSourceFileName(sourceFileName);
+}
+
+LLVMValueRef LLVM_Hs_GetFirstAlias(LLVMModuleRef m) {
+	Module *mod = unwrap(m);
+	Module::alias_iterator i = mod->alias_begin();
+    if (i == mod->alias_end()) {
+        return 0;
+    }
+    return wrap(&*i);
+}
+
+LLVMValueRef LLVM_Hs_GetNextAlias(LLVMValueRef a) {
+	GlobalAlias *alias = unwrap<GlobalAlias>(a);
+	Module::alias_iterator i(alias);
+	if (++i == alias->getParent()->alias_end()) return 0;
+	return wrap(&*i);
+}
+
+Comdat *LLVM_Hs_GetOrInsertCOMDAT(LLVMModuleRef m, const char *name) {
+  return unwrap(m)->getOrInsertComdat(name);
+}
+
+// TODO (cocreature): Figure out if we can just change the linkage here
+LLVMValueRef LLVM_Hs_JustAddAlias(LLVMModuleRef m, LLVMTypeRef ty, unsigned addrspace, const char *name) {
+	return wrap(GlobalAlias::create(unwrap(ty), addrspace, GlobalValue::ExternalLinkage, name, 0, unwrap(m)));
+}
+
+NamedMDNode *LLVM_Hs_GetOrAddNamedMetadata(LLVMModuleRef m, const char *name) {
+	return unwrap(m)->getOrInsertNamedMetadata(name);
+}
+
+NamedMDNode *LLVM_Hs_GetFirstNamedMetadata(LLVMModuleRef m) {
+	Module *mod = unwrap(m);
+	Module::named_metadata_iterator i = mod->named_metadata_begin();
+	return i == mod->named_metadata_end() ? 0 : &*i;
+}
+
+NamedMDNode *LLVM_Hs_GetNextNamedMetadata(NamedMDNode *a) {
+	Module::named_metadata_iterator i(a);
+	if (++i == a->getParent()->named_metadata_end()) return 0;
+	return &*i;
+}
+
+void LLVM_Hs_ModuleAppendInlineAsm(LLVMModuleRef m, const char *s, unsigned l) {
+	unwrap(m)->appendModuleInlineAsm(StringRef(s,l));
+}
+
+const char *LLVM_Hs_ModuleGetInlineAsm(LLVMModuleRef m) {
+	return unwrap(m)->getModuleInlineAsm().c_str();
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/ObjectFile.hs b/src/LLVM/Internal/FFI/ObjectFile.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ObjectFile.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- | <https://llvm.org/doxygen/classllvm_1_1object_1_1ObjectFile.html>
+module LLVM.Internal.FFI.ObjectFile where
+
+import Foreign.Ptr
+
+import LLVM.Prelude
+import LLVM.Internal.FFI.MemoryBuffer
+
+data ObjectFile
+
+foreign import ccall unsafe "LLVMCreateObjectFile" createObjectFile ::
+  Ptr MemoryBuffer -> IO (Ptr ObjectFile)
+
+foreign import ccall unsafe "LLVMDisposeObjectFile" disposeObjectFile ::
+  Ptr ObjectFile -> IO ()
diff --git a/src/LLVM/Internal/FFI/OrcJIT.h b/src/LLVM/Internal/FFI/OrcJIT.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/OrcJIT.h
@@ -0,0 +1,25 @@
+#ifndef __LLVM_INTERNAL_FFI__ORC_JIT__H__
+#define __LLVM_INTERNAL_FFI__ORC_JIT__H__
+
+#define LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(macro) \
+    macro(None)                                      \
+    macro(HasError)                                  \
+    macro(Weak)                                      \
+    macro(Common)                                    \
+    macro(Absolute)                                  \
+    macro(Exported)                                  \
+    macro(Callable)                                  \
+    macro(MaterializationSideEffectsOnly)
+
+typedef enum {
+              LLVMJITSymbolFlagNone = 0,
+              LLVMJITSymbolFlagHasError = 1U << 0,
+              LLVMJITSymbolFlagWeak = 1U << 1,
+              LLVMJITSymbolFlagCommon = 1U << 2,
+              LLVMJITSymbolFlagAbsolute = 1U << 3,
+              LLVMJITSymbolFlagExported = 1U << 4,
+              LLVMJITSymbolFlagCallable = 1U << 5,
+              LLVMJITSymbolFlagMaterializationSideEffectsOnly = 1U << 6
+} LLVMJITSymbolFlags_;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/OrcJIT.hs b/src/LLVM/Internal/FFI/OrcJIT.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/OrcJIT.hs
@@ -0,0 +1,113 @@
+module LLVM.Internal.FFI.OrcJIT where
+
+import LLVM.Prelude
+
+import LLVM.Internal.FFI.DataLayout (DataLayout)
+import LLVM.Internal.FFI.Module (Module)
+import LLVM.Internal.FFI.Target (TargetMachine)
+import LLVM.Internal.FFI.LLVMCTypes
+
+import Foreign.Ptr
+import Foreign.C
+
+newtype TargetAddress = TargetAddress Word64
+
+data JITEvaluatedSymbol
+data ExpectedJITEvaluatedSymbol
+data MangleAndInterner
+data ThreadSafeContext
+data ThreadSafeModule
+data ObjectLayer
+data IRLayer
+data JITDylib
+data ExecutionSession
+data SymbolStringPtr
+
+foreign import ccall safe "LLVM_Hs_createExecutionSession" createExecutionSession ::
+  IO (Ptr ExecutionSession)
+
+foreign import ccall safe "LLVM_Hs_disposeExecutionSession" disposeExecutionSession ::
+  Ptr ExecutionSession -> IO ()
+
+foreign import ccall safe "LLVM_Hs_ExecutionSession_endSession" endSession ::
+  Ptr ExecutionSession -> IO ()
+
+foreign import ccall safe "LLVM_Hs_ExecutionSession_createJITDylib" createJITDylib ::
+  Ptr ExecutionSession -> CString -> IO (Ptr JITDylib)
+
+foreign import ccall safe "LLVM_Hs_ExecutionSession_lookupSymbol" lookupSymbol ::
+  Ptr ExecutionSession -> Ptr JITDylib -> Ptr MangleAndInterner -> CString -> IO (Ptr ExpectedJITEvaluatedSymbol)
+
+foreign import ccall safe "LLVM_Hs_createThreadSafeContext" createThreadSafeContext ::
+  IO (Ptr ThreadSafeContext)
+
+foreign import ccall safe "LLVM_Hs_disposeThreadSafeContext" disposeThreadSafeContext ::
+  Ptr ThreadSafeContext -> IO ()
+
+foreign import ccall safe "LLVM_Hs_cloneAsThreadSafeModule" cloneAsThreadSafeModule ::
+  Ptr Module -> IO (Ptr ThreadSafeModule)
+
+foreign import ccall safe "LLVM_Hs_disposeThreadSafeModule" disposeThreadSafeModule ::
+  Ptr ThreadSafeModule -> IO ()
+
+foreign import ccall safe "LLVM_Hs_createRTDyldObjectLinkingLayer" createRTDyldObjectLinkingLayer ::
+  Ptr ExecutionSession -> IO (Ptr ObjectLayer)
+
+foreign import ccall safe "LLVM_Hs_createObjectLinkingLayer" createObjectLinkingLayer ::
+  Ptr ExecutionSession -> IO (Ptr ObjectLayer)
+
+foreign import ccall safe "LLVM_Hs_ObjectLayerAddObjectFile" objectLayerAddObjectFile ::
+  Ptr ObjectLayer -> Ptr JITDylib -> CString -> IO ()
+
+foreign import ccall safe "LLVM_Hs_disposeObjectLayer" disposeObjectLayer ::
+  Ptr ObjectLayer -> IO ()
+
+foreign import ccall safe "LLVM_Hs_createIRCompileLayer" createIRCompileLayer ::
+  Ptr ExecutionSession -> Ptr ObjectLayer -> Ptr TargetMachine -> IO (Ptr IRLayer)
+
+foreign import ccall safe "LLVM_Hs_disposeIRLayer" disposeIRLayer ::
+  Ptr IRLayer -> IO ()
+
+foreign import ccall safe "LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_forCurrentProcess"
+  addDynamicLibrarySearchGeneratorForCurrentProcess ::
+    Ptr JITDylib -> Ptr DataLayout -> IO ()
+
+foreign import ccall safe "LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_load"
+  addDynamicLibrarySearchGenerator ::
+    Ptr JITDylib -> Ptr DataLayout -> CString -> IO ()
+
+foreign import ccall safe "LLVM_Hs_JITDylib_defineAbsoluteSymbols"
+  defineAbsoluteSymbols :: Ptr JITDylib -> CUInt -> Ptr (Ptr SymbolStringPtr) -> Ptr (Ptr JITEvaluatedSymbol) -> IO ()
+
+foreign import ccall safe "LLVM_Hs_IRLayer_addModule" irLayerAddModule ::
+  Ptr ThreadSafeModule -> Ptr JITDylib -> Ptr DataLayout -> Ptr IRLayer -> IO ()
+
+foreign import ccall safe "LLVM_Hs_getExpectedJITEvaluatedSymbolAddress" getExpectedSymbolAddress ::
+  Ptr ExpectedJITEvaluatedSymbol -> Ptr (OwnerTransfered CString) -> IO TargetAddress
+
+foreign import ccall safe "LLVM_Hs_getExpectedJITEvaluatedSymbolFlags" getExpectedSymbolFlags ::
+  Ptr ExpectedJITEvaluatedSymbol -> IO JITSymbolFlags
+
+foreign import ccall safe "LLVM_Hs_disposeExpectedJITEvaluatedSymbol" disposeExpectedJITEvaluatedSymbol ::
+  Ptr ExpectedJITEvaluatedSymbol -> IO ()
+
+foreign import ccall safe "LLVM_Hs_createJITEvaluatedSymbol" createJITEvaluatedSymbol ::
+  TargetAddress -> JITSymbolFlags -> IO (Ptr JITEvaluatedSymbol)
+
+foreign import ccall safe "LLVM_Hs_disposeJITEvaluatedSymbol" disposeJITEvaluatedSymbol ::
+  Ptr JITEvaluatedSymbol -> IO ()
+
+foreign import ccall safe "LLVM_Hs_createMangleAndInterner" createMangleAndInterner ::
+  Ptr ExecutionSession -> Ptr DataLayout -> IO (Ptr MangleAndInterner)
+
+foreign import ccall safe "LLVM_Hs_disposeMangleAndInterner" disposeMangleAndInterner ::
+  Ptr MangleAndInterner -> IO ()
+
+foreign import ccall safe "LLVM_Hs_MangleAndInterner_call" mangleSymbol ::
+  Ptr MangleAndInterner -> CString -> IO (Ptr SymbolStringPtr)
+
+foreign import ccall safe "LLVM_Hs_SymbolStringPtr_c_str" mangledSymbolString ::
+  Ptr SymbolStringPtr -> IO CString
+
+foreign import ccall safe "LLVM_Hs_disposeSymbolStringPtr" disposeMangledSymbol ::
+  Ptr SymbolStringPtr -> IO ()
diff --git a/src/LLVM/Internal/FFI/OrcJITC.cpp b/src/LLVM/Internal/FFI/OrcJITC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/OrcJITC.cpp
@@ -0,0 +1,258 @@
+#include <iostream>
+#include <memory>
+
+#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
+#include <llvm/ExecutionEngine/Orc/Core.h>
+#include <llvm/ExecutionEngine/Orc/ExecutionUtils.h>
+#include <llvm/ExecutionEngine/Orc/Mangling.h>
+#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
+#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
+#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
+#include <llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h>
+#include <llvm/ExecutionEngine/SectionMemoryManager.h>
+#include <llvm/Bitcode/BitcodeWriter.h>
+#include <llvm/Bitcode/BitcodeReader.h>
+#include <llvm/IR/Module.h>
+#include <llvm-c/Core.h>
+#include <llvm-c/Orc.h>
+
+#include "LLVM/Internal/FFI/OrcJIT.h"
+#include "LLVM/Internal/FFI/Target.hpp"
+
+using namespace llvm;
+using namespace orc;
+
+#define SYMBOL_CASE(x)                                                         \
+    static_assert((unsigned)LLVMJITSymbolFlag##x ==                            \
+                      (unsigned)llvm::JITSymbolFlags::FlagNames::x,            \
+                  "JITSymbolFlag values should agree");
+LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(SYMBOL_CASE)
+
+static JITSymbolFlags unwrap(LLVMJITSymbolFlags_ f) {
+    JITSymbolFlags flags = JITSymbolFlags::None;
+#define ENUM_CASE(x)                                                           \
+    if (f & LLVMJITSymbolFlag##x)                                              \
+        flags |= JITSymbolFlags::x;
+    LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    return flags;
+}
+
+static LLVMJITSymbolFlags_ wrap(JITSymbolFlags f) {
+    unsigned r = 0;
+#define ENUM_CASE(x)                                                           \
+    if (f & JITSymbolFlags::x)                                                 \
+        r |= (unsigned)LLVMJITSymbolFlag##x;
+    LLVM_HS_FOR_EACH_JIT_SYMBOL_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    return LLVMJITSymbolFlags_(r);
+}
+
+extern "C" {
+
+// ExecutionSession
+
+ExecutionSession *LLVM_Hs_createExecutionSession() {
+    return new ExecutionSession();
+}
+
+void LLVM_Hs_disposeExecutionSession(ExecutionSession *es) {
+    delete es;
+}
+
+void LLVM_Hs_ExecutionSession_endSession(ExecutionSession *es) {
+    if (Error err = es->endSession()) {
+        llvm::errs() << err << "\n";
+        // FIXME: Better error handling
+        exit(1);
+    }
+}
+
+// Thread-safe context
+
+ThreadSafeContext* LLVM_Hs_createThreadSafeContext() {
+    return new ThreadSafeContext(std::make_unique<LLVMContext>());
+}
+
+void LLVM_Hs_disposeThreadSafeContext(ThreadSafeContext* ctx) {
+    delete ctx;
+}
+
+// Thread-safe module
+
+// TODO: Figure out a way to do this without cloning the module
+// The cloning is inspired by the code in llvm::orc::cloneToNewContext
+ThreadSafeModule* LLVM_Hs_cloneAsThreadSafeModule(LLVMModuleRef m) {
+    Module* module = unwrap(m);
+    SmallVector<char,1> bitcode;
+    BitcodeWriter writer(bitcode);
+    writer.writeModule(*module);
+    writer.writeSymtab();
+    writer.writeStrtab();
+
+    ThreadSafeContext clone_context(std::make_unique<LLVMContext>());
+    MemoryBufferRef bitcode_ref(StringRef(bitcode.data(), bitcode.size()), "clone bitcode");
+    std::unique_ptr<Module> cloned_module = cantFail(
+        parseBitcodeFile(bitcode_ref, *clone_context.getContext()));
+    cloned_module->setModuleIdentifier(module->getName());
+    return new ThreadSafeModule(std::move(cloned_module), std::move(clone_context));
+}
+
+void LLVM_Hs_disposeThreadSafeModule(ThreadSafeModule* module) {
+    delete module;
+}
+
+// Object layer
+
+ObjectLayer* LLVM_Hs_createRTDyldObjectLinkingLayer(ExecutionSession* es) {
+    return new RTDyldObjectLinkingLayer(*es, []() {
+        return std::make_unique<SectionMemoryManager>();
+    });
+}
+
+ObjectLayer* LLVM_Hs_createObjectLinkingLayer(ExecutionSession* es) {
+    return new ObjectLinkingLayer(*es, std::make_unique<jitlink::InProcessMemoryManager>());
+}
+
+void LLVM_Hs_ObjectLayerAddObjectFile(ObjectLayer* ol, JITDylib* dylib, const char* path) {
+  ExitOnError ExitOnErr;
+  if (auto errorOrBuffer = MemoryBuffer::getFile(path)) {
+    ExitOnErr(ol->add(*dylib, std::move(errorOrBuffer.get())));
+  } else exit(1);
+}
+
+void LLVM_Hs_disposeObjectLayer(ObjectLayer* ol) {
+    delete ol;
+}
+
+// Compile layer
+
+IRLayer* LLVM_Hs_createIRCompileLayer(ExecutionSession* es, ObjectLayer* baseLayer, LLVMTargetMachineRef tm) {
+    return new IRCompileLayer(*es, *baseLayer, std::make_unique<SimpleCompiler>(SimpleCompiler(*unwrap(tm))));
+}
+
+void LLVM_Hs_disposeIRLayer(IRLayer* il) {
+    delete il;
+}
+
+void LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_forCurrentProcess(JITDylib* dylib, LLVMTargetDataRef dataLayout) {
+    auto dataLayoutCpp = *unwrap(dataLayout);
+    ExitOnError ExitOnErr;
+    dylib->addGenerator(
+      ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
+          dataLayoutCpp.getGlobalPrefix())));
+}
+
+void LLVM_Hs_JITDylib_addDynamicLibrarySearchGenerator_load(JITDylib* dylib, LLVMTargetDataRef dataLayout, const char* name) {
+    auto dataLayoutCpp = *unwrap(dataLayout);
+    ExitOnError ExitOnErr;
+    dylib->addGenerator(
+      ExitOnErr(orc::DynamicLibrarySearchGenerator::Load(
+          name, dataLayoutCpp.getGlobalPrefix())));
+}
+
+void LLVM_Hs_JITDylib_defineAbsoluteSymbols(
+    JITDylib* dylib, unsigned num_symbols, const SymbolStringPtr** names, const JITEvaluatedSymbol** symbols) {
+  orc::SymbolMap map;
+  for (unsigned i = 0; i < num_symbols; ++i) {
+    map[*names[i]] = *symbols[i];
+  }
+  if (Error err = dylib->define(orc::absoluteSymbols(std::move(map)))) {
+    llvm::errs() << err << "\n";
+    // FIXME: Better error handling
+    exit(1);
+  }
+}
+
+// Warning: This consumes the module.
+void LLVM_Hs_IRLayer_addModule(ThreadSafeModule* tsm, JITDylib* dylib, LLVMTargetDataRef dataLayout, IRLayer* il) {
+    auto dataLayoutCpp = *unwrap(dataLayout);
+    tsm->withModuleDo([&](auto& module) {
+        if (module.getDataLayout().isDefault()) {
+            module.setDataLayout(dataLayoutCpp);
+        }
+    });
+    if (Error err = il->add(*dylib, std::move(*tsm))) {
+        llvm::errs() << err << "\n";
+        // FIXME: Better error handling
+        exit(1);
+    }
+}
+
+JITDylib* LLVM_Hs_ExecutionSession_createJITDylib(ExecutionSession* es, const char* name) {
+    if (auto dylibOrErr = es->createJITDylib(name)) {
+        auto& dylib = *dylibOrErr;
+        return &dylib;
+    } else {
+        Error err = dylibOrErr.takeError();
+        llvm::errs() << err << "\n";
+        // FIXME: Better error handling
+        exit(1);
+    }
+}
+
+
+Expected<JITEvaluatedSymbol>* LLVM_Hs_ExecutionSession_lookupSymbol(
+    ExecutionSession* es, JITDylib* dylib,
+    MangleAndInterner* mangler, const char* name) {
+    // Printing here will show unresolved symbols.
+    // es->dump(llvm::errs());
+    return new Expected<JITEvaluatedSymbol>(es->lookup({dylib}, (*mangler)(name)));
+}
+
+uint64_t LLVM_Hs_getExpectedJITEvaluatedSymbolAddress(
+  Expected<JITEvaluatedSymbol>* symbolPtr,
+  char** errMsg) {
+    auto& symbol = *symbolPtr;
+    *errMsg = nullptr;
+    if (symbol) {
+        return symbol->getAddress();
+    } else {
+        *errMsg = strdup(toString(symbol.takeError()).c_str());
+        return 0;
+    }
+}
+
+LLVMJITSymbolFlags_ LLVM_Hs_getExpectedJITEvaluatedSymbolFlags(
+  Expected<JITEvaluatedSymbol>* symbolPtr) {
+    auto& symbol = *symbolPtr;
+    if (!symbol) {
+        return LLVMJITSymbolFlagHasError;
+    }
+    return wrap(symbol->getFlags());
+}
+
+JITEvaluatedSymbol* LLVM_Hs_createJITEvaluatedSymbol(uint64_t ptr, LLVMJITSymbolFlags_ flags) {
+    return new JITEvaluatedSymbol(ptr, unwrap(flags));
+}
+
+void LLVM_Hs_disposeJITEvaluatedSymbol(JITEvaluatedSymbol* symbol) {
+    delete symbol;
+}
+
+void LLVM_Hs_disposeExpectedJITEvaluatedSymbol(Expected<JITEvaluatedSymbol>* symbol) {
+    delete symbol;
+}
+
+MangleAndInterner* LLVM_Hs_createMangleAndInterner(ExecutionSession* es,
+                                                   LLVMTargetDataRef dl) {
+    return new MangleAndInterner(*es, *unwrap(dl));
+}
+
+void LLVM_Hs_disposeMangleAndInterner(MangleAndInterner* mangler) {
+    delete mangler;
+}
+
+SymbolStringPtr* LLVM_Hs_MangleAndInterner_call(MangleAndInterner* mangler, const char* name) {
+    return new SymbolStringPtr((*mangler)(name));
+}
+
+const char* LLVM_Hs_SymbolStringPtr_c_str(SymbolStringPtr* ptr) {
+    return (*(*ptr)).data();
+}
+
+void LLVM_Hs_disposeSymbolStringPtr(SymbolStringPtr* ptr) {
+    delete ptr;
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/PassManager.hs b/src/LLVM/Internal/FFI/PassManager.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/PassManager.hs
@@ -0,0 +1,134 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  ForeignFunctionInterface,
+  CPP
+  #-}
+
+module LLVM.Internal.FFI.PassManager where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+import LLVM.Internal.FFI.Cleanup
+import LLVM.Internal.FFI.Module
+import LLVM.Internal.FFI.Target
+import LLVM.Internal.FFI.Transforms
+
+import qualified LLVM.Transforms as G
+
+data PassManager
+
+foreign import ccall unsafe "LLVMCreatePassManager" createPassManager ::
+  IO (Ptr PassManager)
+
+foreign import ccall unsafe "LLVMDisposePassManager" disposePassManager ::
+  Ptr PassManager -> IO ()
+
+foreign import ccall unsafe "LLVMRunPassManager" runPassManager ::
+  Ptr PassManager -> Ptr Module -> IO CUInt
+
+foreign import ccall unsafe "LLVMCreateFunctionPassManagerForModule" createFunctionPassManagerForModule ::
+  Ptr Module -> IO (Ptr PassManager)
+
+foreign import ccall unsafe "LLVMInitializeFunctionPassManager" initializeFunctionPassManager ::
+  Ptr PassManager -> IO CUInt
+
+foreign import ccall unsafe "LLVMRunFunctionPassManager" runFunctionPassManager ::
+  Ptr PassManager -> Ptr Value -> IO CUInt
+
+foreign import ccall unsafe "LLVMFinalizeFunctionPassManager" finalizeFunctionPassManager ::
+  Ptr PassManager -> IO CUInt
+
+foreign import ccall unsafe "LLVMAddAnalysisPasses" addAnalysisPasses ::
+  Ptr TargetMachine -> Ptr PassManager -> IO ()
+
+foreign import ccall unsafe "LLVMAddTargetLibraryInfo" addTargetLibraryInfoPass' ::
+  Ptr TargetLibraryInfo -> Ptr PassManager -> IO ()
+
+addTargetLibraryInfoPass :: Ptr PassManager -> Ptr TargetLibraryInfo -> IO ()
+addTargetLibraryInfoPass = flip addTargetLibraryInfoPass'
+
+$(do
+  let declareForeign :: TH.Name -> [TH.Type] -> TH.DecsQ
+      declareForeign hName extraParams = do
+        let n = TH.nameBase hName
+            passTypeMapping :: TH.Type -> TH.TypeQ
+            passTypeMapping t = case t of
+              TH.ConT h | h == ''Word -> [t| CUInt |]
+                        | h == ''G.GCOVVersion -> [t| CString |]
+              -- some of the LLVM methods for making passes use "-1" as a special value
+              -- handle those here
+              TH.AppT (TH.ConT mby) t' | mby == ''Maybe ->
+                case t' of
+                  TH.ConT h | h == ''Bool -> [t| NothingAsMinusOne Bool |]
+                            | h == ''Word -> [t| NothingAsMinusOne Word |]
+                            | h == ''FilePath -> [t| NothingAsEmptyString CString |]
+                  _ -> typeMapping t
+              _ -> typeMapping t
+        foreignDecl
+          (cName n)
+          ("add" ++ n ++ "Pass")
+          ([[t| Ptr PassManager |]]
+           ++ [[t| Ptr TargetMachine |] | needsTargetMachine n]
+           ++ map passTypeMapping extraParams)
+          (TH.tupleT 0)
+#if __GLASGOW_HASKELL__ < 800
+  TH.TyConI (TH.DataD _ _ _ cons _) <- TH.reify ''G.Pass
+#else
+  TH.TyConI (TH.DataD _ _ _ _ cons _) <- TH.reify ''G.Pass
+#endif
+  liftM concat $ forM cons $ \con -> case con of
+    TH.RecC n l -> declareForeign n [ t | (_,_,t) <- l ]
+    TH.NormalC n [] -> declareForeign n []
+    _ -> error "pass descriptor constructors with fields need to be records"
+ )
+
+data PassManagerBuilder
+
+foreign import ccall unsafe "LLVMPassManagerBuilderCreate" passManagerBuilderCreate ::
+    IO (Ptr PassManagerBuilder)
+
+foreign import ccall unsafe "LLVMPassManagerBuilderDispose" passManagerBuilderDispose ::
+    Ptr PassManagerBuilder -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderSetOptLevel" passManagerBuilderSetOptLevel ::
+    Ptr PassManagerBuilder -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderSetSizeLevel" passManagerBuilderSetSizeLevel ::
+    Ptr PassManagerBuilder -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableUnitAtATime" passManagerBuilderSetDisableUnitAtATime ::
+    Ptr PassManagerBuilder -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableUnrollLoops" passManagerBuilderSetDisableUnrollLoops ::
+    Ptr PassManagerBuilder -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderSetDisableSimplifyLibCalls" passManagerBuilderSetDisableSimplifyLibCalls ::
+    Ptr PassManagerBuilder -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderUseInlinerWithThreshold" passManagerBuilderUseInlinerWithThreshold ::
+    Ptr PassManagerBuilder -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderPopulateFunctionPassManager" passManagerBuilderPopulateFunctionPassManager ::
+    Ptr PassManagerBuilder -> Ptr PassManager -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderPopulateModulePassManager" passManagerBuilderPopulateModulePassManager ::
+    Ptr PassManagerBuilder -> Ptr PassManager -> IO ()
+
+foreign import ccall unsafe "LLVMPassManagerBuilderPopulateLTOPassManager" passManagerBuilderPopulateLTOPassManager ::
+    Ptr PassManagerBuilder -> Ptr PassManager -> CUChar -> CUChar -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_PassManagerBuilderSetLibraryInfo" passManagerBuilderSetLibraryInfo ::
+    Ptr PassManagerBuilder -> Ptr TargetLibraryInfo -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_PassManagerBuilderSetLoopVectorize" passManagerBuilderSetLoopVectorize ::
+    Ptr PassManagerBuilder -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_PassManagerBuilderSetSuperwordLevelParallelismVectorize" passManagerBuilderSetSuperwordLevelParallelismVectorize ::
+    Ptr PassManagerBuilder -> LLVMBool -> IO ()
diff --git a/src/LLVM/Internal/FFI/PassManagerC.cpp b/src/LLVM/Internal/FFI/PassManagerC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/PassManagerC.cpp
@@ -0,0 +1,206 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/Internalize.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Vectorize.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
+#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
+#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
+#include "llvm/Transforms/Utils.h"
+#include "llvm/LinkAllPasses.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/Transforms/PassManagerBuilder.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Target/TargetMachine.h"
+
+#include "llvm-c/Core.h"
+
+using namespace llvm;
+
+extern "C" {
+typedef struct LLVMOpaqueVectorizationConfig *LLVMVectorizationConfigRef;
+typedef struct LLVMOpaqueTargetLowering *LLVMTargetLoweringRef;
+typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
+}
+
+namespace llvm {
+inline TargetLowering *unwrap(LLVMTargetLoweringRef P) {
+	return reinterpret_cast<TargetLowering *>(P);
+}
+
+inline LLVMTargetLoweringRef wrap(const TargetLowering *P) {
+	return reinterpret_cast<LLVMTargetLoweringRef>(const_cast<TargetLowering *>(P));
+}
+
+inline TargetMachine *unwrap(LLVMTargetMachineRef P) {
+	return reinterpret_cast<TargetMachine*>(P);
+}
+
+inline LLVMTargetMachineRef wrap(const TargetMachine *P) {
+	return reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine *>(P));
+}
+
+inline TargetLibraryInfoImpl *unwrap(LLVMTargetLibraryInfoRef P) {
+  return reinterpret_cast<TargetLibraryInfoImpl*>(P);
+}
+
+}
+
+extern "C" {
+
+#define LLVM_HS_FOR_EACH_PASS_WITHOUT_LLVM_C_BINDING(macro) \
+	macro(BreakCriticalEdges) \
+	macro(DeadCodeElimination) \
+	macro(DemoteRegisterToMemory) \
+	macro(LCSSA) \
+	macro(LoopInstSimplify) \
+	macro(LowerAtomic) \
+	macro(LowerSwitch) \
+	macro(MergeFunctions) \
+	macro(PartialInlining) \
+	macro(Sinking) \
+	macro(StripDeadDebugInfo) \
+	macro(StripDebugDeclare) \
+	macro(StripNonDebugSymbols) \
+
+#define ENUM_CASE(p)								\
+void LLVM_Hs_Add ## p ## Pass(LLVMPassManagerRef PM) {	\
+	unwrap(PM)->add(create ## p ## Pass());			\
+}
+LLVM_HS_FOR_EACH_PASS_WITHOUT_LLVM_C_BINDING(ENUM_CASE)
+#undef ENUM_CASE
+
+void LLVM_Hs_AddCodeGenPreparePass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createCodeGenPreparePass());
+}
+
+void LLVM_Hs_AddGlobalValueNumberingPass(LLVMPassManagerRef PM, LLVMBool noLoads) {
+	unwrap(PM)->add(createGVNPass(noLoads));
+}
+
+void LLVM_Hs_AddInternalizePass(LLVMPassManagerRef PM, unsigned nExports, const char **exports) {
+    std::vector<std::string> exportList(nExports);
+    for (unsigned i = 0; i < nExports; ++i) {
+        exportList.at(i) = exports[i];
+    }
+    std::function<bool(const GlobalValue &)> mustPreserveGV = [exportList](const GlobalValue & gv) {
+        for (const auto& exp : exportList) {
+            if (gv.getName().equals(exp)) {
+                return true;
+            }
+        }
+        return false;
+    };
+    unwrap(PM)->add(createInternalizePass(std::move(mustPreserveGV)));
+}
+
+void LLVM_Hs_AddLoopStrengthReducePass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createLoopStrengthReducePass());
+}
+
+void LLVM_Hs_AddLowerInvokePass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createLowerInvokePass());
+}
+
+void LLVM_Hs_AddSROAPass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createSROAPass());
+}
+
+void LLVM_Hs_AddGCOVProfilerPass(
+	LLVMPassManagerRef PM,
+	LLVMBool emitNotes,
+	LLVMBool emitData,
+	const char *version,
+	LLVMBool noRedZone,
+	LLVMBool atomic,
+	const char *filter,
+	const char *exclude
+) {
+	auto options = GCOVOptions::getDefault();
+	options.EmitNotes = emitNotes;
+	options.EmitData = emitData;
+	std::copy(version, version+4, options.Version);
+	options.NoRedZone = noRedZone;
+	options.Atomic = atomic;
+	options.Filter = filter;
+	options.Exclude = exclude;
+	unwrap(PM)->add(createGCOVProfilerPass(options));
+}
+
+void LLVM_Hs_AddAddressSanitizerFunctionPass(
+	LLVMPassManagerRef PM
+) {
+	unwrap(PM)->add(createAddressSanitizerFunctionPass());
+}
+
+void LLVM_Hs_AddAddressSanitizerModulePass(
+	LLVMPassManagerRef PM
+) {
+	unwrap(PM)->add(createModuleAddressSanitizerLegacyPassPass());
+}
+
+void LLVM_Hs_AddMemorySanitizerPass(
+	LLVMPassManagerRef PM,
+	LLVMBool trackOrigins,
+	LLVMBool recover,
+	LLVMBool kernel
+) {
+	unwrap(PM)->add(createMemorySanitizerLegacyPassPass(
+    {trackOrigins, static_cast<bool>(recover), static_cast<bool>(kernel)}));
+}
+
+void LLVM_Hs_AddThreadSanitizerPass(
+	LLVMPassManagerRef PM
+) {
+	unwrap(PM)->add(createThreadSanitizerLegacyPassPass());
+}
+
+void LLVM_Hs_AddBoundsCheckingPass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createBoundsCheckingLegacyPass());
+}
+
+void LLVM_Hs_AddIPSCCPPass(LLVMPassManagerRef PM) {
+	unwrap(PM)->add(createIPSCCPPass());
+}
+
+void LLVM_Hs_AddLoopVectorizePass(
+	LLVMPassManagerRef PM,
+	LLVMBool interleaveOnlyWhenForced,
+	LLVMBool vectorizeOnlyWhenForced
+) {
+	unwrap(PM)->add(createLoopVectorizePass(interleaveOnlyWhenForced, vectorizeOnlyWhenForced));
+}
+
+void LLVM_Hs_PassManagerBuilderSetLibraryInfo(
+	LLVMPassManagerBuilderRef PMB,
+	LLVMTargetLibraryInfoRef l
+) {
+	// The PassManager frees the TargetLibraryInfo when done,
+	// but we also free our ref, so give it a new copy.
+	unwrap(PMB)->LibraryInfo = new TargetLibraryInfoImpl(*unwrap(l));
+}
+
+void LLVM_Hs_PassManagerBuilderSetLoopVectorize(
+	LLVMPassManagerBuilderRef PMB,
+	LLVMBool runLoopVectorization
+) {
+	unwrap(PMB)->LoopVectorize = runLoopVectorization;
+}
+
+void LLVM_Hs_PassManagerBuilderSetSuperwordLevelParallelismVectorize(
+	LLVMPassManagerBuilderRef PMB,
+	LLVMBool runSLPVectorization
+) {
+	unwrap(PMB)->SLPVectorize = runSLPVectorization;
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/PtrHierarchy.hs b/src/LLVM/Internal/FFI/PtrHierarchy.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/PtrHierarchy.hs
@@ -0,0 +1,303 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  FunctionalDependencies,
+  UndecidableInstances
+  #-}
+-- | This module defines typeclasses to represent the relationships of an object-oriented inheritance hierarchy
+module LLVM.Internal.FFI.PtrHierarchy where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+
+-- | a class to represent safe casting of pointers to objects of descendant-classes to ancestor-classes.
+class DescendentOf a b where
+    upCast :: Ptr b -> Ptr a
+    upCast = castPtr
+
+-- | trivial casts
+instance {-# OVERLAPPING #-} DescendentOf a a where
+    upCast = id
+
+-- | a class to represent direct parent-child relationships
+class ChildOf b c | c -> b
+
+-- | ancestor-descentant relationships are build out of parent-child relationships
+instance (DescendentOf a b, ChildOf b c) => DescendentOf a c
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Value.html>
+data Value
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Constant.html>
+data Constant
+
+instance ChildOf User Constant
+
+-- | <http://llvm.org/doxygen/classllvm_1_1GlobalValue.html>
+data GlobalValue
+
+instance ChildOf Constant GlobalValue
+
+-- | <http://llvm.org/doxygen/classllvm_1_1GlobalObject.html>
+data GlobalObject
+
+instance ChildOf GlobalValue GlobalObject
+
+-- | <http://llvm.org/doxygen/classllvm_1_1GlobalVariable.html>
+data GlobalVariable
+
+instance ChildOf GlobalObject GlobalVariable
+
+-- | <http://llvm.org/doxygen/classllvm_1_1GlobalAlias.html>
+data GlobalAlias
+
+instance ChildOf GlobalValue GlobalAlias
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Function.html>
+data Function
+
+instance ChildOf GlobalObject Function
+
+-- | <http://llvm.org/doxygen/classllvm_1_1BasicBlock.html>
+data BasicBlock
+
+instance ChildOf Value BasicBlock
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Argument.html>
+data Parameter
+
+instance ChildOf Value Parameter
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Instruction.html>
+data Instruction
+
+instance ChildOf User Instruction
+
+-- | <http://llvm.org/doxygen/classllvm_1_1UnaryOperator.html>
+data UnaryOperator
+
+-- This is not strictly true in the sense of the definition of the typeclass
+-- ChildOf, since Instruction -> UnaryInstruction -> UnaryOperator is the
+-- derivation. However, we never need to reference UnaryInstruction methods
+-- so we can elide it. It is valid to cast a UnaryOperator* to an Instruction*.
+instance ChildOf Instruction UnaryOperator
+
+-- | <http://llvm.org/doxygen/classllvm_1_1BinaryOperator.html>
+data BinaryOperator
+
+instance ChildOf Instruction BinaryOperator
+
+-- | <http://llvm.org/doxygen/classllvm_1_1User.html>
+data User
+
+instance ChildOf Value User
+
+-- | <http://llvm.org/doxygen/classllvm_1_1MDNode.html>
+data MDNode
+
+instance ChildOf Metadata MDNode
+
+data MDTuple
+
+instance ChildOf MDNode MDTuple
+
+-- | <http://llvm.org/doxygen/classllvm_1_1MDString.html>
+data MDString
+
+instance ChildOf Metadata MDString
+
+-- | http://llvm.org/doxygen/classllvm_1_1ValueAsMetadata.html
+data MDValue
+
+instance ChildOf Metadata MDValue
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIExpression.html
+data DIExpression
+
+instance ChildOf MDNode DIExpression
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIGlobalVariableExpression.html
+data DIGlobalVariableExpression
+
+instance ChildOf MDNode DIGlobalVariableExpression
+
+-- | https://llvm.org/doxygen/classllvm_1_1DILocation.html
+data DILocation
+
+instance ChildOf MDNode DILocation
+
+-- | https://llvm.org/doxygen/classllvm_1_1DINode.html
+data DINode
+
+instance ChildOf MDNode DINode
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIImportedEntity.html
+data DIImportedEntity
+
+instance ChildOf DINode DIImportedEntity
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIObjCProperty.html
+data DIObjCProperty
+
+instance ChildOf DINode DIObjCProperty
+
+-- | https://llvm.org/doxygen/classllvm_1_1DISubrange.html
+data DISubrange
+
+instance ChildOf DINode DISubrange
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIEnumerator.html
+data DIEnumerator
+
+instance ChildOf DINode DIEnumerator
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIVariable.html
+data DIVariable
+
+instance ChildOf DINode DIVariable
+
+-- | https://llvm.org/doxygen/classllvm_1_1DILocalVariable.html
+data DILocalVariable
+
+instance ChildOf DIVariable DILocalVariable
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIGlobalVariable.html
+data DIGlobalVariable
+
+instance ChildOf DIVariable DIGlobalVariable
+
+-- | https://llvm.org/doxygen/classllvm_1_1DITemplateParameter.html
+data DITemplateParameter
+
+instance ChildOf DINode DITemplateParameter
+
+-- | https://llvm.org/doxygen/classllvm_1_1DITemplateTypeParameter.html
+data DITemplateTypeParameter
+
+instance ChildOf DITemplateParameter DITemplateTypeParameter
+
+-- | https://llvm.org/doxygen/classllvm_1_1DITemplateValueParameter.html
+data DITemplateValueParameter
+
+instance ChildOf DITemplateParameter DITemplateValueParameter
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIScope.html
+data DIScope
+
+instance ChildOf DINode DIScope
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIModule.html
+data DIModule
+
+instance ChildOf DIScope DIModule
+
+-- | https://llvm.org/doxygen/classllvm_1_1DINamespace.html
+data DINamespace
+
+instance ChildOf DIScope DINamespace
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIFile.html
+data DIFile
+
+instance ChildOf DIScope DIFile
+
+-- | https://llvm.org/doxygen/classllvm_1_1DICompileUnit.html
+data DICompileUnit
+
+instance ChildOf DIScope DICompileUnit
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIType.html
+data DIType
+
+instance ChildOf DIScope DIType
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIBasicType.html
+data DIBasicType
+
+instance ChildOf DIType DIBasicType
+
+-- | https://llvm.org/doxygen/classllvm_1_1DIDerivedType.html
+data DIDerivedType
+
+instance ChildOf DIType DIDerivedType
+
+-- | https://llvm.org/doxygen/classllvm_1_1DISubroutineType.html
+data DISubroutineType
+
+instance ChildOf DIType DISubroutineType
+
+-- | https://llvm.org/doxygen/classllvm_1_1DICompositeType.html
+data DICompositeType
+
+instance ChildOf DIType DICompositeType
+
+-- | https://llvm.org/doxygen/classllvm_1_1DILocalScope.html
+data DILocalScope
+
+instance ChildOf DIScope DILocalScope
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DILexicalBlockBase.html>
+data DILexicalBlockBase
+
+instance ChildOf DILocalScope DILexicalBlockBase
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DILexicalBlock.html>
+data DILexicalBlock
+
+instance ChildOf DILexicalBlockBase DILexicalBlock
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DILexicalBlockFile.html>
+data DILexicalBlockFile
+
+instance ChildOf DILexicalBlockBase DILexicalBlockFile
+
+-- | <https://llvm.org/doxygen/classllvm_1_1DISubprogram.html>
+data DISubprogram
+
+instance ChildOf DILocalScope DISubprogram
+
+-- <https://llvm.org/doxygen/classllvm_1_1DIMacroNode.html>
+data DIMacroNode
+
+instance ChildOf MDNode DIMacroNode
+
+-- <https://llvm.org/doxygen/classllvm_1_1DIMacro.html>
+data DIMacro
+
+instance ChildOf DIMacroNode DIMacro
+
+-- <https://llvm.org/doxygen/classllvm_1_1DIMacroFile.html>
+data DIMacroFile
+
+instance ChildOf DIMacroNode DIMacroFile
+
+-- | <http://llvm.org/doxygen/classllvm_1_1NamedMDNode.html>
+data NamedMetadata
+
+-- | <http://llvm.org/doxygen/classllvm_1_1InlineAsm.html>
+data InlineAsm
+
+instance ChildOf Value InlineAsm
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Type.html>
+data Type
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Metadata.html>
+data Metadata
+
+-- | <http://www.llvm.org/docs/doxygen/html/classllvm_1_1MetadataAsValue.html>
+data MetadataAsVal
+
+instance ChildOf Value MetadataAsVal
+
+-- | <http://llvm.org/docs/doxygen/html/classllvm_1_1raw__ostream.html>
+data RawOStream
+
+-- | <http://llvm.org/docs/doxygen/html/classllvm_1_1raw__pwrite__stream.html>
+data RawPWriteStream
+
+instance ChildOf RawOStream RawPWriteStream
+
+-- | <https://llvm.org/doxygen/classllvm_1_1StringRef.html>
+data StringRef
diff --git a/src/LLVM/Internal/FFI/RTDyldMemoryManager.cpp b/src/LLVM/Internal/FFI/RTDyldMemoryManager.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/RTDyldMemoryManager.cpp
@@ -0,0 +1,14 @@
+#define __STDC_LIMIT_MACROS
+
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+
+using namespace llvm;
+
+extern "C" {
+
+uint64_t LLVM_Hs_GetSymbolAddressInProcess(const char *name) {
+    std::string nameStr(name);
+    return RTDyldMemoryManager::getSymbolAddressInProcess(nameStr);
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/RTDyldMemoryManager.hs b/src/LLVM/Internal/FFI/RTDyldMemoryManager.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/RTDyldMemoryManager.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+-- | FFI functions for handling the RTDyldMemoryManager class
+module LLVM.Internal.FFI.RTDyldMemoryManager where
+
+import LLVM.Prelude
+
+import Foreign.C.String
+
+-- | <https://llvm.org/doxygen/classllvm_1_1RTDyldMemoryManager.html#a5fee247bdc0c5af393b66bfd73a0a347>
+foreign import ccall safe "LLVM_Hs_GetSymbolAddressInProcess" getSymbolAddressInProcess ::
+  CString -> IO Word64
diff --git a/src/LLVM/Internal/FFI/RawOStream.hs b/src/LLVM/Internal/FFI/RawOStream.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/RawOStream.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.RawOStream where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+import Control.Exception (bracket)
+
+import LLVM.Internal.FFI.ByteRangeCallback
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+type RawPWriteStreamCallback = Ptr RawPWriteStream -> IO ()
+
+foreign import ccall "wrapper" wrapRawPWriteStreamCallback ::
+  RawPWriteStreamCallback -> IO (FunPtr RawPWriteStreamCallback)
+
+foreign import ccall safe "LLVM_Hs_WithFileRawPWriteStream" withFileRawPWriteStream' ::
+  CString -> LLVMBool -> LLVMBool -> Ptr (OwnerTransfered CString) -> FunPtr RawPWriteStreamCallback -> IO LLVMBool
+
+withFileRawPWriteStream :: CString -> LLVMBool -> LLVMBool -> Ptr (OwnerTransfered CString) -> RawPWriteStreamCallback -> IO LLVMBool
+withFileRawPWriteStream p ex bin err c =
+  bracket (wrapRawPWriteStreamCallback c) freeHaskellFunPtr (withFileRawPWriteStream' p ex bin err)
+
+foreign import ccall safe "LLVM_Hs_WithBufferRawPWriteStream" withBufferRawPWriteStream' ::
+  FunPtr ByteRangeCallback -> FunPtr RawPWriteStreamCallback -> IO ()
+
+withBufferRawPWriteStream :: ByteRangeCallback -> RawPWriteStreamCallback -> IO ()
+withBufferRawPWriteStream oc c =
+  bracket (wrapRawPWriteStreamCallback c) freeHaskellFunPtr $ \c ->
+  bracket (wrapByteRangeCallback oc) freeHaskellFunPtr $ \oc ->
+    withBufferRawPWriteStream' oc c
diff --git a/src/LLVM/Internal/FFI/RawOStreamC.cpp b/src/LLVM/Internal/FFI/RawOStreamC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/RawOStreamC.cpp
@@ -0,0 +1,35 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm-c/Core.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMBool
+LLVM_Hs_WithFileRawPWriteStream(const char *filename, LLVMBool excl,
+                                LLVMBool text, char **error,
+                                void (&callback)(raw_pwrite_stream &ostream)) {
+    std::error_code e;
+    raw_fd_ostream os(filename, e,
+                      excl ? sys::fs::CD_CreateNew : sys::fs::CD_OpenAlways,
+                      sys::fs::FA_Write,
+                      text ? sys::fs::OF_Text : sys::fs::OF_None);
+    if (e) {
+        *error = strdup(e.message().c_str());
+        return false;
+    }
+    callback(os);
+    return true;
+}
+
+void LLVM_Hs_WithBufferRawPWriteStream(
+    void (&outputCallback)(const char *start, size_t length),
+    void (&streamCallback)(raw_pwrite_stream &ostream)) {
+    SmallString<0> s;
+    raw_svector_ostream os(s);
+    streamCallback(os);
+    outputCallback(os.str().data(), s.size());
+}
+}
diff --git a/src/LLVM/Internal/FFI/SMDiagnostic.h b/src/LLVM/Internal/FFI/SMDiagnostic.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/SMDiagnostic.h
@@ -0,0 +1,15 @@
+#ifndef __LLVM_INTERNAL_FFI__SMDIAGNOSTIC__
+#define __LLVM_INTERNAL_FFI__SMDIAGNOSTIC__
+
+#define LLVM_HS_FOR_EACH_DIAGNOSTIC_KIND(macro) \
+	macro(Error) \
+	macro(Warning) \
+	macro(Note)
+
+typedef enum {
+#define ENUM_CASE(k) LLVMDiagnosticKind ## k,
+LLVM_HS_FOR_EACH_DIAGNOSTIC_KIND(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMDiagnosticKind;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/SMDiagnostic.hs b/src/LLVM/Internal/FFI/SMDiagnostic.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/SMDiagnostic.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+-- | FFI functions for handling the LLVM SMDiagnostic class
+module LLVM.Internal.FFI.SMDiagnostic where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+data SMDiagnostic
+
+-- | allocate an SMDiagnostic object
+foreign import ccall unsafe "LLVM_Hs_CreateSMDiagnostic" createSMDiagnostic ::
+  IO (Ptr SMDiagnostic)
+
+foreign import ccall unsafe "LLVM_Hs_DisposeSMDiagnostic" disposeSMDiagnostic ::
+  Ptr SMDiagnostic -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticKind" getSMDiagnosticKind ::
+  Ptr SMDiagnostic -> IO DiagnosticKind
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticLineNo" getSMDiagnosticLineNo ::
+  Ptr SMDiagnostic -> IO CInt 
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticColumnNo" getSMDiagnosticColumnNo ::
+  Ptr SMDiagnostic -> IO CInt 
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticFilename" getSMDiagnosticFilename ::
+  Ptr SMDiagnostic -> Ptr CUInt -> IO CString 
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticMessage" getSMDiagnosticMessage ::
+  Ptr SMDiagnostic -> Ptr CUInt -> IO CString 
+
+foreign import ccall unsafe "LLVM_Hs_GetSMDiagnosticLineContents" getSMDiagnosticLineContents ::
+  Ptr SMDiagnostic -> Ptr CUInt -> IO CString 
+
diff --git a/src/LLVM/Internal/FFI/SMDiagnosticC.cpp b/src/LLVM/Internal/FFI/SMDiagnosticC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/SMDiagnosticC.cpp
@@ -0,0 +1,42 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/LLVMContext.h"
+
+#include "llvm/Support/SourceMgr.h"
+#include "llvm-c/Core.h"
+
+#include "LLVM/Internal/FFI/SMDiagnostic.h"
+
+using namespace llvm;
+
+extern "C" {
+
+SMDiagnostic *LLVM_Hs_CreateSMDiagnostic() { return new SMDiagnostic(); }
+void LLVM_Hs_DisposeSMDiagnostic(SMDiagnostic *p) { delete p; }
+
+LLVMDiagnosticKind LLVM_Hs_GetSMDiagnosticKind(SMDiagnostic *p) {
+	switch(p->getKind()) {
+#define ENUM_CASE(k) case SourceMgr::DK_ ## k: return LLVMDiagnosticKind ## k;
+		LLVM_HS_FOR_EACH_DIAGNOSTIC_KIND(ENUM_CASE)
+#undef ENUM_CASE
+	default: return LLVMDiagnosticKind(0);
+	}
+}
+
+int LLVM_Hs_GetSMDiagnosticLineNo(SMDiagnostic *p) { return p->getLineNo(); }
+int LLVM_Hs_GetSMDiagnosticColumnNo(SMDiagnostic *p) { return p->getColumnNo(); }
+
+const char *LLVM_Hs_GetSMDiagnosticFilename(SMDiagnostic *p, unsigned *len) { 
+	*len = p->getFilename().size();
+	return p->getFilename().data();
+}
+const char *LLVM_Hs_GetSMDiagnosticMessage(SMDiagnostic *p, unsigned *len) {
+	*len = p->getMessage().size();
+	return p->getMessage().data();
+}
+const char *LLVM_Hs_GetSMDiagnosticLineContents(SMDiagnostic *p, unsigned *len) {
+	*len = p->getLineContents().size();
+	return p->getLineContents().data();
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/ShortByteString.hs b/src/LLVM/Internal/FFI/ShortByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ShortByteString.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE CPP #-}
+module LLVM.Internal.FFI.ShortByteString
+  ( packCString
+  , packCStringLen
+  , useAsCString
+  , useAsCStringLen
+  ) where
+
+
+
+#if MIN_VERSION_bytestring(0,10,9)
+import Data.ByteString.Short
+#else
+import LLVM.Prelude
+import Data.ByteString.Internal (c_strlen)
+import Data.ByteString.Short.Internal
+import qualified Data.ByteString.Short as ByteString
+import Foreign.C.String
+import Foreign.Marshal.Alloc
+import Foreign.Storable
+
+
+{-# INLINABLE packCString #-}
+packCString :: CString -> IO ShortByteString
+packCString cstr = do
+    len <- c_strlen cstr
+    packCStringLen (cstr, fromIntegral len)
+
+{-# INLINABLE packCStringLen #-}
+packCStringLen :: CStringLen -> IO ShortByteString
+packCStringLen (cstr, len) | len >= 0 = createFromPtr cstr len
+packCStringLen (_, len) =
+    error ("negative length: " ++ show len)
+
+{-# INLINABLE useAsCString #-}
+useAsCString :: ShortByteString -> (CString -> IO a) -> IO a
+useAsCString bs action =
+ allocaBytes (l+1) $ \buf -> do
+     copyToPtr bs 0 buf (fromIntegral l)
+     pokeByteOff buf l (0::Word8)
+     action buf
+ where l = ByteString.length bs
+
+{-# INLINABLE useAsCStringLen #-}
+useAsCStringLen :: ShortByteString -> (CStringLen -> IO a) -> IO a
+useAsCStringLen bs action =
+ allocaBytes l $ \buf -> do
+     copyToPtr bs 0 buf (fromIntegral l)
+     action (buf, l)
+ where l = ByteString.length bs
+#endif
diff --git a/src/LLVM/Internal/FFI/Target.h b/src/LLVM/Internal/FFI/Target.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Target.h
@@ -0,0 +1,183 @@
+#ifndef __LLVM_INTERNAL_FFI__TARGET__H__
+#define __LLVM_INTERNAL_FFI__TARGET__H__
+
+#define LLVM_HS_FOR_EACH_RELOC_MODEL(macro) \
+  macro(Default, Default)                         \
+  macro(Static, Static)                           \
+  macro(PIC, PIC_)                                \
+  macro(DynamicNoPic, DynamicNoPIC)
+
+#define LLVM_HS_FOR_EACH_CODE_MODEL(macro) \
+  macro(Default)                                \
+  macro(JITDefault)                             \
+  macro(Small)                                  \
+  macro(Kernel)                                 \
+  macro(Medium)                                 \
+  macro(Large)
+
+#define LLVM_HS_FOR_EACH_CODE_GEN_OPT_LEVEL(macro) \
+  macro(None)                                           \
+  macro(Less)                                           \
+  macro(Default)                                        \
+  macro(Aggressive)
+
+#define LLVM_HS_FOR_EACH_CODE_GEN_FILE_TYPE(macro)  \
+  macro(Assembly)                                       \
+  macro(Object)
+
+#define LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(macro)  \
+  macro(UnsafeFPMath)                                   \
+  macro(NoInfsFPMath)                                   \
+  macro(NoNaNsFPMath)                                   \
+  macro(NoTrappingFPMath)                               \
+  macro(NoSignedZerosFPMath)                            \
+  macro(HonorSignDependentRoundingFPMathOption)         \
+  macro(NoZerosInBSS)                                   \
+  macro(GuaranteedTailCallOpt)                          \
+  macro(StackSymbolOrdering)                            \
+  macro(EnableFastISel)                                 \
+  macro(EnableGlobalISel)                               \
+  macro(UseInitArray)                                   \
+  macro(DisableIntegratedAS)                            \
+  macro(RelaxELFRelocations)                            \
+  macro(FunctionSections)                               \
+  macro(DataSections)                                   \
+  macro(IgnoreXCOFFVisibility)                          \
+  macro(UniqueSectionNames)                             \
+  macro(UniqueBasicBlockSectionNames)                   \
+  macro(TrapUnreachable)                                \
+  macro(NoTrapAfterNoreturn)                            \
+  macro(EmulatedTLS)                                    \
+  macro(ExplicitEmulatedTLS)                            \
+  macro(EnableIPRA)                                     \
+  macro(EmitStackSizeSection)                           \
+  macro(EnableMachineOutliner)                          \
+  macro(EnableMachineFunctionSplitter)                  \
+  macro(SupportsDefaultOutlining)                       \
+  macro(EmitAddrsig)                                    \
+  macro(EmitCallSiteInfo)                               \
+  macro(SupportsDebugEntryValues)                       \
+  macro(EnableDebugEntryValues)                         \
+  macro(ValueTrackingVariableLocations)                 \
+  macro(ForceDwarfFrameSection)                         \
+  macro(XRayOmitFunctionIndex)                          \
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_TargetOptionFlag_ ## n,
+  LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_TargetOptionFlag;
+
+#define LLVM_HS_FOR_EACH_MC_TARGET_OPTION_FLAG(macro)  \
+  macro(MCRelaxAll)                                     \
+  macro(MCNoExecStack)                                  \
+  macro(MCFatalWarnings)                                \
+  macro(MCNoWarn)                                       \
+  macro(MCNoDeprecatedWarn)                             \
+  macro(MCSaveTempLabels)                               \
+  macro(MCUseDwarfDirectory)                            \
+  macro(MCIncrementalLinkerCompatible)                  \
+  macro(ShowMCEncoding)                                 \
+  macro(ShowMCInst)                                     \
+  macro(AsmVerbose)                                     \
+  macro(PreserveAsmComments)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_MCTargetOptionFlag_ ## n,
+  LLVM_HS_FOR_EACH_MC_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_MCTargetOptionFlag;
+
+#define LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(macro) \
+    macro(None) \
+    macro(GNU) \
+    macro(Z)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_DebugCompressionType_ ## n,
+    LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_DebugCompressionType;
+
+#define LLVM_HS_FOR_EACH_FLOAT_ABI(macro) \
+  macro(Default)                                \
+  macro(Soft)                                   \
+  macro(Hard)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_FloatABI_ ## n,
+  LLVM_HS_FOR_EACH_FLOAT_ABI(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_FloatABI;
+
+#define LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(macro) \
+  macro(Fast)                                           \
+  macro(Standard)                                       \
+  macro(Strict)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_FPOpFusionMode_ ## n,
+  LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_FPOpFusionMode;
+
+#define LLVM_HS_FOR_EACH_THREAD_MODEL(macro) \
+  macro(POSIX) \
+  macro(Single)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_ThreadModel_ ## n,
+  LLVM_HS_FOR_EACH_THREAD_MODEL(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_ThreadModel;
+
+#define LLVM_HS_FOR_EACH_EABI(macro) \
+  macro(Unknown)                                        \
+  macro(Default)                                        \
+  macro(EABI4)                                          \
+  macro(EABI5)                                          \
+  macro(GNU)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_EABI_ ## n,
+  LLVM_HS_FOR_EACH_EABI(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_EABI;
+
+#define LLVM_HS_FOR_EACH_DEBUGGER_KIND(macro) \
+  macro(Default)                                        \
+  macro(GDB)                                            \
+  macro(LLDB)                                           \
+  macro(SCE)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_DebuggerKind_ ## n,
+  LLVM_HS_FOR_EACH_DEBUGGER_KIND(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_DebuggerKind;
+
+#define LLVM_HS_FOR_EACH_FP_DENORMAL_MODE(macro) \
+  macro(IEEE)                                           \
+  macro(PreserveSign)                                   \
+  macro(PositiveZero)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_FPDenormalMode_ ## n,
+  LLVM_HS_FOR_EACH_FP_DENORMAL_MODE(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_FPDenormalMode;
+
+#define LLVM_HS_FOR_EACH_EXCEPTION_HANDLING(macro) \
+  macro(None)                                           \
+  macro(DwarfCFI)                                       \
+  macro(SjLj)                                           \
+  macro(ARM)                                            \
+  macro(WinEH)
+
+typedef enum {
+#define ENUM_CASE(n) LLVM_Hs_ExceptionHandling_ ## n,
+  LLVM_HS_FOR_EACH_EXCEPTION_HANDLING(ENUM_CASE)
+#undef ENUM_CASE
+} LLVM_Hs_ExceptionHandling;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Target.hpp b/src/LLVM/Internal/FFI/Target.hpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Target.hpp
@@ -0,0 +1,11 @@
+#ifndef __LLVM_INTERNAL_FFI__TARGET__HPP__
+#define __LLVM_INTERNAL_FFI__TARGET__HPP__
+
+#include "llvm-c/TargetMachine.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
+}
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Target.hs b/src/LLVM/Internal/FFI/Target.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Target.hs
@@ -0,0 +1,190 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  GeneralizedNewtypeDeriving
+  #-}
+module LLVM.Internal.FFI.Target where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.DataLayout
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.MemoryBuffer
+import LLVM.Internal.FFI.Module
+import LLVM.Internal.FFI.PtrHierarchy
+
+data Target
+
+foreign import ccall unsafe "LLVM_Hs_InitializeNativeTarget" initializeNativeTarget ::
+    IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_LookupTarget" lookupTarget ::
+    CString -> CString -> Ptr (OwnerTransfered CString) -> Ptr (OwnerTransfered CString) -> IO (Ptr Target)
+
+data TargetOptions
+data MCTargetOptions
+
+foreign import ccall unsafe "LLVM_Hs_CreateTargetOptions" createTargetOptions ::
+  IO (Ptr TargetOptions)
+
+foreign import ccall unsafe "LLVM_Hs_SetTargetOptionFlag" setTargetOptionFlag ::
+  Ptr TargetOptions -> TargetOptionFlag -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetTargetOptionFlag" getTargetOptionsFlag ::
+  Ptr TargetOptions -> TargetOptionFlag -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_SetMCTargetOptionFlag" setMCTargetOptionFlag ::
+  Ptr MCTargetOptions -> MCTargetOptionFlag -> LLVMBool -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetMCTargetOptionFlag" getMCTargetOptionsFlag ::
+  Ptr MCTargetOptions -> MCTargetOptionFlag -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_GetCompressDebugSections" getCompressDebugSections ::
+  Ptr TargetOptions -> IO DebugCompressionType
+
+foreign import ccall unsafe "LLVM_Hs_SetCompressDebugSections" setCompressDebugSections ::
+  Ptr TargetOptions -> DebugCompressionType -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_SetStackAlignmentOverride" setStackAlignmentOverride ::
+  Ptr TargetOptions -> CUInt -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetStackAlignmentOverride" getStackAlignmentOverride ::
+  Ptr TargetOptions -> IO CUInt
+
+foreign import ccall unsafe "LLVM_Hs_SetFloatABIType" setFloatABIType ::
+  Ptr TargetOptions -> FloatABIType -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetFloatABIType" getFloatABIType ::
+  Ptr TargetOptions -> IO FloatABIType
+
+foreign import ccall unsafe "LLVM_Hs_SetAllowFPOpFusion" setAllowFPOpFusion ::
+  Ptr TargetOptions -> FPOpFusionMode -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetAllowFPOpFusion" getAllowFPOpFusion ::
+  Ptr TargetOptions -> IO FPOpFusionMode
+
+foreign import ccall unsafe "LLVM_Hs_SetThreadModel" setThreadModel ::
+  Ptr TargetOptions -> ThreadModel -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetThreadModel" getThreadModel ::
+  Ptr TargetOptions -> IO ThreadModel
+
+foreign import ccall unsafe "LLVM_Hs_SetEABIVersion" setEABIVersion ::
+  Ptr TargetOptions -> EABI -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetEABIVersion" getEABIVersion ::
+  Ptr TargetOptions -> IO EABI
+
+foreign import ccall unsafe "LLVM_Hs_SetDebuggerTuning" setDebuggerTuning ::
+  Ptr TargetOptions -> DebuggerKind -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetDebuggerTuning" getDebuggerTuning ::
+  Ptr TargetOptions -> IO DebuggerKind
+
+foreign import ccall unsafe "LLVM_Hs_SetFPDenormalMode" setFPDenormalMode ::
+  Ptr TargetOptions -> FPDenormalMode -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetFPDenormalMode" getFPDenormalMode ::
+  Ptr TargetOptions -> IO FPDenormalMode
+
+foreign import ccall unsafe "LLVM_Hs_SetExceptionModel" setExceptionModel ::
+  Ptr TargetOptions -> ExceptionHandling -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_GetExceptionModel" getExceptionModel ::
+  Ptr TargetOptions -> IO ExceptionHandling
+
+foreign import ccall unsafe "LLVM_Hs_DisposeTargetOptions" disposeTargetOptions ::
+  Ptr TargetOptions -> IO ()
+
+data TargetMachine
+
+foreign import ccall unsafe "LLVM_Hs_CreateTargetMachine" createTargetMachine ::
+  Ptr Target
+  -> CString
+  -> CString
+  -> CString
+  -> Ptr TargetOptions
+  -> RelocModel
+  -> CodeModel
+  -> CodeGenOptLevel
+  -> IO (Ptr TargetMachine)
+
+foreign import ccall unsafe "LLVMDisposeTargetMachine" disposeTargetMachine ::
+  Ptr TargetMachine -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_TargetMachineOptions" targetMachineOptions ::
+  Ptr TargetMachine -> IO (Ptr TargetOptions)
+
+foreign import ccall unsafe "LLVM_Hs_MCTargetOptions" machineCodeOptions ::
+  Ptr TargetOptions -> IO (Ptr MCTargetOptions)
+
+foreign import ccall unsafe "LLVM_Hs_TargetMachineEmit" targetMachineEmit ::
+  Ptr TargetMachine
+  -> Ptr Module
+  -> Ptr RawPWriteStream
+  -> CodeGenFileType
+  -> Ptr (OwnerTransfered CString)
+  -> IO LLVMBool
+
+foreign import ccall unsafe "LLVMTargetMachineEmitToFile" targetMachineEmitToFile ::
+  Ptr TargetMachine
+  -> Ptr Module
+  -> CString
+  -> CodeGenFileType
+  -> Ptr (OwnerTransfered CString)
+  -> IO LLVMBool
+
+foreign import ccall unsafe "LLVMTargetMachineEmitToMemoryBuffer" targetMachineEmitToMemoryBuffer ::
+  Ptr TargetMachine
+  -> Ptr Module
+  -> CodeGenFileType
+  -> Ptr (OwnerTransfered CString)
+  -> Ptr (Ptr MemoryBuffer)
+  -> IO LLVMBool
+
+data TargetLowering
+
+-- foreign import ccall unsafe "LLVM_Hs_GetTargetLowering" getTargetLowering ::
+--   Ptr TargetMachine -> IO (Ptr TargetLowering)
+
+foreign import ccall unsafe "LLVMGetTargetMachineTriple" getTargetMachineTriple ::
+  Ptr TargetMachine -> IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_GetDefaultTargetTriple" getDefaultTargetTriple :: 
+  IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_GetProcessTargetTriple" getProcessTargetTriple :: 
+  IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_GetHostCPUName" getHostCPUName :: 
+  Ptr CSize -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_GetHostCPUFeatures" getHostCPUFeatures ::
+  IO (OwnerTransfered CString)
+
+foreign import ccall unsafe "LLVM_Hs_GetTargetMachineDataLayout" getTargetMachineDataLayout ::
+  Ptr TargetMachine -> IO (OwnerTransfered CString)
+
+data TargetLibraryInfo
+
+foreign import ccall unsafe "LLVM_Hs_CreateTargetLibraryInfo" createTargetLibraryInfo ::
+  CString -> IO (Ptr TargetLibraryInfo)
+
+foreign import ccall unsafe "LLVM_Hs_GetLibFunc" getLibFunc ::
+  Ptr TargetLibraryInfo -> CString -> Ptr LibFunc -> IO LLVMBool
+
+foreign import ccall unsafe "LLVM_Hs_LibFuncGetName" libFuncGetName ::
+  Ptr TargetLibraryInfo -> LibFunc -> Ptr CSize -> IO CString
+
+foreign import ccall unsafe "LLVM_Hs_LibFuncSetAvailableWithName" libFuncSetAvailableWithName ::
+  Ptr TargetLibraryInfo -> LibFunc -> CString -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_DisposeTargetLibraryInfo" disposeTargetLibraryInfo ::
+  Ptr TargetLibraryInfo -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_InitializeAllTargets" initializeAllTargets :: IO ()
+
+foreign import ccall unsafe "LLVMCreateTargetDataLayout" createTargetDataLayout ::
+  Ptr TargetMachine -> IO (Ptr DataLayout)
diff --git a/src/LLVM/Internal/FFI/TargetC.cpp b/src/LLVM/Internal/FFI/TargetC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/TargetC.cpp
@@ -0,0 +1,586 @@
+#define __STDC_LIMIT_MACROS
+#include "LLVM/Internal/FFI/ErrorHandling.hpp"
+#include "LLVM/Internal/FFI/LibFunc.h"
+#include "LLVM/Internal/FFI/Target.h"
+#include "LLVM/Internal/FFI/Target.hpp"
+#include "llvm-c/Core.h"
+#include "llvm-c/Target.h"
+#include "llvm-c/TargetMachine.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/ExecutionEngine/Interpreter.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/CodeGenCWrappers.h"
+#include "llvm/Target/TargetMachine.h"
+
+using namespace llvm;
+
+namespace llvm {
+// Taken from llvm/lib/Target/TargetMachineC.cpp
+// These functions need to be marked as static to avoid undefined behavior
+// due to multiple definitions
+static LLVMTargetRef wrap(const Target *P) {
+    return reinterpret_cast<LLVMTargetRef>(const_cast<Target *>(P));
+}
+
+static Target *unwrap(LLVMTargetRef P) { return reinterpret_cast<Target *>(P); }
+
+static inline TargetLibraryInfoImpl *unwrap(LLVMTargetLibraryInfoRef P) {
+    return reinterpret_cast<TargetLibraryInfoImpl *>(P);
+}
+
+static inline LLVMTargetLibraryInfoRef wrap(const TargetLibraryInfoImpl *P) {
+    TargetLibraryInfoImpl *X = const_cast<TargetLibraryInfoImpl *>(P);
+    return reinterpret_cast<LLVMTargetLibraryInfoRef>(X);
+}
+
+static FloatABI::ABIType unwrap(LLVM_Hs_FloatABI x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_FloatABI_##x:                                                 \
+        return FloatABI::x;
+        LLVM_HS_FOR_EACH_FLOAT_ABI(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return FloatABI::ABIType(0);
+    }
+}
+
+static LibFunc unwrap(LLVMLibFunc x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVMLibFunc__##x:                                                     \
+        return LibFunc_##x;
+        LLVM_HS_FOR_EACH_LIB_FUNC(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LibFunc(0);
+    }
+}
+
+static LLVMLibFunc wrap(LibFunc x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LibFunc_##x:                                                          \
+        return LLVMLibFunc__##x;
+        LLVM_HS_FOR_EACH_LIB_FUNC(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVMLibFunc(0);
+    }
+}
+
+static LLVM_Hs_FloatABI wrap(FloatABI::ABIType x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case FloatABI::x:                                                          \
+        return LLVM_Hs_FloatABI_##x;
+        LLVM_HS_FOR_EACH_FLOAT_ABI(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_FloatABI(0);
+    }
+}
+
+static FPOpFusion::FPOpFusionMode unwrap(LLVM_Hs_FPOpFusionMode x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_FPOpFusionMode_##x:                                           \
+        return FPOpFusion::x;
+        LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return FPOpFusion::FPOpFusionMode(0);
+    }
+}
+
+static LLVM_Hs_FPOpFusionMode wrap(FPOpFusion::FPOpFusionMode x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case FPOpFusion::x:                                                        \
+        return LLVM_Hs_FPOpFusionMode_##x;
+        LLVM_HS_FOR_EACH_FP_OP_FUSION_MODE(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_FPOpFusionMode(0);
+    }
+}
+
+static ThreadModel::Model unwrap(LLVM_Hs_ThreadModel x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_ThreadModel_##x:                                              \
+        return ThreadModel::x;
+        LLVM_HS_FOR_EACH_THREAD_MODEL(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return ThreadModel::Model(0);
+    }
+}
+
+static LLVM_Hs_ThreadModel wrap(ThreadModel::Model x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case ThreadModel::x:                                                       \
+        return LLVM_Hs_ThreadModel_##x;
+        LLVM_HS_FOR_EACH_THREAD_MODEL(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_ThreadModel(0);
+    }
+}
+static EABI unwrap(LLVM_Hs_EABI x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_EABI_##x:                                                     \
+        return EABI::x;
+        LLVM_HS_FOR_EACH_EABI(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return EABI(0);
+    }
+}
+
+static LLVM_Hs_EABI wrap(EABI x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case EABI::x:                                                              \
+        return LLVM_Hs_EABI_##x;
+        LLVM_HS_FOR_EACH_EABI(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_EABI(0);
+    }
+}
+
+static DebuggerKind unwrap(LLVM_Hs_DebuggerKind x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_DebuggerKind_##x:                                             \
+        return DebuggerKind::x;
+        LLVM_HS_FOR_EACH_DEBUGGER_KIND(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return DebuggerKind(0);
+    }
+}
+
+static LLVM_Hs_DebuggerKind wrap(DebuggerKind x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case DebuggerKind::x:                                                      \
+        return LLVM_Hs_DebuggerKind_##x;
+        LLVM_HS_FOR_EACH_DEBUGGER_KIND(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_DebuggerKind(0);
+    }
+}
+
+static DenormalMode::DenormalModeKind unwrap(LLVM_Hs_FPDenormalMode x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_FPDenormalMode_##x:                                           \
+      return DenormalMode::DenormalModeKind::x;
+        LLVM_HS_FOR_EACH_FP_DENORMAL_MODE(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+          return DenormalMode::DenormalModeKind(0);
+    }
+}
+
+static LLVM_Hs_FPDenormalMode wrap(DenormalMode::DenormalModeKind x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case DenormalMode::DenormalModeKind::x:                                           \
+        return LLVM_Hs_FPDenormalMode_##x;
+        LLVM_HS_FOR_EACH_FP_DENORMAL_MODE(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_FPDenormalMode(0);
+    }
+}
+static ExceptionHandling unwrap(LLVM_Hs_ExceptionHandling x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case LLVM_Hs_ExceptionHandling_##x:                                        \
+        return ExceptionHandling::x;
+        LLVM_HS_FOR_EACH_EXCEPTION_HANDLING(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return ExceptionHandling(0);
+    }
+}
+
+static LLVM_Hs_ExceptionHandling wrap(ExceptionHandling x) {
+    switch (x) {
+#define ENUM_CASE(x)                                                           \
+    case ExceptionHandling::x:                                                 \
+        return LLVM_Hs_ExceptionHandling_##x;
+        LLVM_HS_FOR_EACH_EXCEPTION_HANDLING(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        return LLVM_Hs_ExceptionHandling(0);
+    }
+}
+
+} // namespace llvm
+
+extern "C" {
+
+LLVMBool LLVM_Hs_InitializeNativeTarget() {
+    return LLVMInitializeNativeTarget() || InitializeNativeTargetAsmPrinter() ||
+           InitializeNativeTargetAsmParser();
+}
+
+LLVMTargetRef LLVM_Hs_LookupTarget(const char *arch, const char *ctriple,
+                                   const char **tripleOut,
+                                   const char **cerror) {
+    std::string error;
+    Triple triple(ctriple);
+    if (const Target *result =
+            TargetRegistry::lookupTarget(arch, triple, error)) {
+        *tripleOut = strdup(triple.getTriple().c_str());
+        return wrap(result);
+    }
+    *cerror = strdup(error.c_str());
+    return 0;
+}
+
+TargetOptions *LLVM_Hs_CreateTargetOptions() {
+    TargetOptions *to = new TargetOptions();
+    return to;
+}
+
+void LLVM_Hs_SetTargetOptionFlag(TargetOptions *to, LLVM_Hs_TargetOptionFlag f,
+                                 unsigned v) {
+    switch (f) {
+#define ENUM_CASE(op)                                                          \
+    case LLVM_Hs_TargetOptionFlag_##op:                                        \
+        to->op = v ? 1 : 0;                                                    \
+        break;
+        LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    }
+}
+
+void LLVM_Hs_SetMCTargetOptionFlag(MCTargetOptions *to,
+                                   LLVM_Hs_MCTargetOptionFlag f, unsigned v) {
+    switch (f) {
+#define ENUM_CASE(op)                                                          \
+    case LLVM_Hs_MCTargetOptionFlag_##op:                                      \
+        to->op = v ? 1 : 0;                                                    \
+        break;
+        LLVM_HS_FOR_EACH_MC_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    }
+}
+
+static llvm::DebugCompressionType
+unwrap(LLVM_Hs_DebugCompressionType compressionType) {
+    switch (compressionType) {
+#define ENUM_CASE(op)                                                          \
+    case LLVM_Hs_DebugCompressionType_##op:                                    \
+        return llvm::DebugCompressionType::op;
+        LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        reportFatalError("Unknown debug compression type");
+        return llvm::DebugCompressionType::None;
+    }
+}
+
+static LLVM_Hs_DebugCompressionType
+wrap(llvm::DebugCompressionType compressionType) {
+    switch (compressionType) {
+#define ENUM_CASE(op)                                                          \
+    case llvm::DebugCompressionType::op:                                       \
+        return LLVM_Hs_DebugCompressionType_##op;
+        LLVM_HS_FOR_EACH_DEBUG_COMPRESSION_TYPE(ENUM_CASE)
+#undef ENUM_CASE
+    default: {
+        reportFatalError("Unknown debug compression type");
+        return LLVM_Hs_DebugCompressionType_None;
+    }
+    }
+}
+
+void LLVM_Hs_SetCompressDebugSections(TargetOptions *to,
+                                      LLVM_Hs_DebugCompressionType compress) {
+    to->CompressDebugSections = unwrap(compress);
+}
+
+LLVM_Hs_DebugCompressionType
+LLVM_Hs_GetCompressDebugSections(TargetOptions *to) {
+    return wrap(to->CompressDebugSections);
+}
+
+unsigned LLVM_Hs_GetTargetOptionFlag(TargetOptions *to,
+                                     LLVM_Hs_TargetOptionFlag f) {
+    switch (f) {
+#define ENUM_CASE(op)                                                          \
+    case LLVM_Hs_TargetOptionFlag_##op:                                        \
+        return to->op;
+        LLVM_HS_FOR_EACH_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        reportFatalError("Unknown target option flag");
+        return 0;
+    }
+}
+
+unsigned LLVM_Hs_GetMCTargetOptionFlag(MCTargetOptions *to,
+                                       LLVM_Hs_MCTargetOptionFlag f) {
+    switch (f) {
+#define ENUM_CASE(op)                                                          \
+    case LLVM_Hs_MCTargetOptionFlag_##op:                                      \
+        return to->op;
+        LLVM_HS_FOR_EACH_MC_TARGET_OPTION_FLAG(ENUM_CASE)
+#undef ENUM_CASE
+    default:
+        reportFatalError("Unknown machine code target option flag");
+        return 0;
+    }
+}
+
+void LLVM_Hs_SetStackAlignmentOverride(TargetOptions *to, unsigned v) {
+    to->StackAlignmentOverride = v;
+}
+
+unsigned LLVM_Hs_GetStackAlignmentOverride(TargetOptions *to) {
+    return to->StackAlignmentOverride;
+}
+
+void LLVM_Hs_SetFloatABIType(TargetOptions *to, LLVM_Hs_FloatABI v) {
+    to->FloatABIType = unwrap(v);
+}
+
+LLVM_Hs_FloatABI LLVM_Hs_GetFloatABIType(TargetOptions *to) {
+    return wrap(to->FloatABIType);
+}
+
+void LLVM_Hs_SetAllowFPOpFusion(TargetOptions *to, LLVM_Hs_FPOpFusionMode v) {
+    to->AllowFPOpFusion = unwrap(v);
+}
+
+LLVM_Hs_FPOpFusionMode LLVM_Hs_GetAllowFPOpFusion(TargetOptions *to) {
+    return wrap(to->AllowFPOpFusion);
+}
+
+void LLVM_Hs_SetThreadModel(TargetOptions *to, LLVM_Hs_ThreadModel v) {
+    to->ThreadModel = unwrap(v);
+}
+
+LLVM_Hs_ThreadModel LLVM_Hs_GetThreadModel(TargetOptions *to) {
+    return wrap(to->ThreadModel);
+}
+
+void LLVM_Hs_SetEABIVersion(TargetOptions *to, LLVM_Hs_EABI v) {
+    to->EABIVersion = unwrap(v);
+}
+
+LLVM_Hs_EABI LLVM_Hs_GetEABIVersion(TargetOptions *to) {
+    return wrap(to->EABIVersion);
+}
+
+void LLVM_Hs_SetDebuggerTuning(TargetOptions *to, LLVM_Hs_DebuggerKind v) {
+    to->DebuggerTuning = unwrap(v);
+}
+
+LLVM_Hs_DebuggerKind LLVM_Hs_GetDebuggerTuning(TargetOptions *to) {
+    return wrap(to->DebuggerTuning);
+}
+
+void LLVM_Hs_SetFPDenormalMode(TargetOptions *to, LLVM_Hs_FPDenormalMode v) {
+    auto denormalModeKind = unwrap(v);
+    DenormalMode denormalMode{denormalModeKind, denormalModeKind};
+    to->setFPDenormalMode(denormalMode);
+}
+
+LLVM_Hs_FPDenormalMode LLVM_Hs_GetFPDenormalMode(TargetOptions *to) {
+    auto denormalMode = to->getRawFPDenormalMode();
+    assert(denormalMode.isSimple() && "Input and output kinds must match");
+    return wrap(denormalMode.Input);
+}
+
+void LLVM_Hs_SetExceptionModel(TargetOptions *to, LLVM_Hs_ExceptionHandling v) {
+    to->ExceptionModel = unwrap(v);
+}
+
+LLVM_Hs_ExceptionHandling LLVM_Hs_GetExceptionModel(TargetOptions *to) {
+    return wrap(to->ExceptionModel);
+}
+
+void LLVM_Hs_DisposeTargetOptions(TargetOptions *t) { delete t; }
+
+// const TargetLowering *LLVM_Hs_GetTargetLowering(LLVMTargetMachineRef t)
+// {
+// 	return unwrap(t)->getTargetLowering();
+// }
+
+char *LLVM_Hs_GetDefaultTargetTriple() {
+    return strdup(sys::getDefaultTargetTriple().c_str());
+}
+
+char *LLVM_Hs_GetProcessTargetTriple() {
+    return strdup(sys::getProcessTriple().c_str());
+}
+
+const char *LLVM_Hs_GetHostCPUName(size_t &len) {
+    StringRef r = sys::getHostCPUName();
+    len = r.size();
+    return r.data();
+}
+
+char *LLVM_Hs_GetHostCPUFeatures() {
+    StringMap<bool> featureMap;
+    std::string features;
+    if (sys::getHostCPUFeatures(featureMap)) {
+        bool first = true;
+        for (llvm::StringMap<bool>::const_iterator it = featureMap.begin();
+             it != featureMap.end(); ++it) {
+            if (!first) {
+                features += ",";
+            }
+            first = false;
+            features += (it->second ? "+" : "-") + it->first().str();
+        }
+    }
+    return strdup(features.c_str());
+}
+
+char *LLVM_Hs_GetTargetMachineDataLayout(LLVMTargetMachineRef t) {
+    return strdup(
+        unwrap(t)->createDataLayout().getStringRepresentation().c_str());
+}
+
+LLVMTargetLibraryInfoRef LLVM_Hs_CreateTargetLibraryInfo(const char *triple) {
+    const TargetLibraryInfoImpl *p = new TargetLibraryInfoImpl(Triple(triple));
+    return wrap(p);
+}
+
+LLVMBool LLVM_Hs_GetLibFunc(LLVMTargetLibraryInfoRef l, const char *funcName,
+                            LLVMLibFunc *f) {
+    LibFunc func;
+    LLVMBool result = unwrap(l)->getLibFunc(funcName, func);
+    *f = wrap(func);
+    return result;
+}
+
+const char *LLVM_Hs_LibFuncGetName(LLVMTargetLibraryInfoRef l, LLVMLibFunc f,
+                                   size_t *nameSize) {
+    TargetLibraryInfo impl(*unwrap(l));
+    StringRef s = impl.getName(unwrap(f));
+    *nameSize = s.size();
+    return s.data();
+}
+
+void LLVM_Hs_LibFuncSetAvailableWithName(LLVMTargetLibraryInfoRef l,
+                                         LLVMLibFunc f, const char *name) {
+    unwrap(l)->setAvailableWithName(unwrap(f), name);
+}
+
+void LLVM_Hs_DisposeTargetLibraryInfo(LLVMTargetLibraryInfoRef l) {
+    delete unwrap(l);
+}
+
+void LLVM_Hs_InitializeAllTargets() {
+    InitializeAllTargetInfos();
+    InitializeAllTargets();
+    InitializeAllTargetMCs();
+    InitializeAllAsmPrinters();
+    // None of the other components are bound yet
+}
+
+LLVMTargetMachineRef LLVM_Hs_CreateTargetMachine(
+    LLVMTargetRef T, const char *Triple, const char *CPU, const char *Features,
+    TargetOptions *TO, LLVMRelocMode Reloc, LLVMCodeModel CodeModel,
+    LLVMCodeGenOptLevel Level) {
+    Optional<Reloc::Model> RM;
+    switch (Reloc) {
+    case LLVMRelocStatic:
+        RM = Reloc::Static;
+        break;
+    case LLVMRelocPIC:
+        RM = Reloc::PIC_;
+        break;
+    case LLVMRelocDynamicNoPic:
+        RM = Reloc::DynamicNoPIC;
+        break;
+    default:
+        break;
+    }
+
+    bool JIT;
+    Optional<CodeModel::Model> CM = unwrap(CodeModel, JIT);
+
+    CodeGenOpt::Level OL;
+    switch (Level) {
+    case LLVMCodeGenLevelNone:
+        OL = CodeGenOpt::None;
+        break;
+    case LLVMCodeGenLevelLess:
+        OL = CodeGenOpt::Less;
+        break;
+    case LLVMCodeGenLevelAggressive:
+        OL = CodeGenOpt::Aggressive;
+        break;
+    default:
+        OL = CodeGenOpt::Default;
+        break;
+    }
+
+    return wrap(unwrap(T)->createTargetMachine(Triple, CPU, Features, *TO, RM,
+                                               CM, OL, JIT));
+}
+
+TargetOptions *LLVM_Hs_TargetMachineOptions(LLVMTargetMachineRef TM) {
+    return &unwrap(TM)->Options;
+}
+
+MCTargetOptions *LLVM_Hs_MCTargetOptions(TargetOptions *to) {
+    return &to->MCOptions;
+}
+
+// This is identical to LLVMTargetMachineEmit but LLVM doesn’t expose this
+// function so we copy it here.
+LLVMBool LLVM_Hs_TargetMachineEmit(LLVMTargetMachineRef T, LLVMModuleRef M,
+                                   raw_pwrite_stream *OS,
+                                   LLVMCodeGenFileType codegen,
+                                   char **ErrorMessage) {
+    TargetMachine *TM = unwrap(T);
+    Module *Mod = unwrap(M);
+
+    legacy::PassManager pass;
+
+    std::string error;
+
+    Mod->setDataLayout(TM->createDataLayout());
+
+    CodeGenFileType ft;
+    switch (codegen) {
+    case LLVMAssemblyFile:
+        ft = CGFT_AssemblyFile;
+        break;
+    default:
+        ft = CGFT_ObjectFile;
+        break;
+    }
+    if (TM->addPassesToEmitFile(pass, *OS, nullptr, ft)) {
+        error = "TargetMachine can't emit a file of this type";
+        *ErrorMessage = strdup(error.c_str());
+        return true;
+    }
+
+    pass.run(*Mod);
+
+    OS->flush();
+    return false;
+}
+}
diff --git a/src/LLVM/Internal/FFI/Threading.hs b/src/LLVM/Internal/FFI/Threading.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Threading.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+module LLVM.Internal.FFI.Threading where
+
+import LLVM.Prelude
+
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+foreign import ccall unsafe "LLVMIsMultithreaded" isMultithreaded ::
+  IO LLVMBool
diff --git a/src/LLVM/Internal/FFI/Transforms.hs b/src/LLVM/Internal/FFI/Transforms.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Transforms.hs
@@ -0,0 +1,75 @@
+-- | Code used with Template Haskell to build the FFI for transform passes.
+module LLVM.Internal.FFI.Transforms where
+
+import LLVM.Prelude
+
+-- | does the constructor for this pass require a TargetMachine object
+needsTargetMachine :: String -> Bool
+needsTargetMachine "CodeGenPrepare" = True
+needsTargetMachine _ = False
+
+-- | Translate a Haskell name (used in the public Haskell interface, typically not abbreviated)
+-- | for a pass into the (sometimes obscure, sometimes abbreviated) name used in the LLVM C interface.
+-- | This translation includes, by choice of prefix, whether the C interface implementation is found in
+-- | the LLVM distribution ("LLVM" prefix) or either not available or broken there and so implemented
+-- | as part of this Haskell package ("LLVM_Hs_" prefix).
+cName :: String -> String
+cName n =
+    let core = case n of
+            "AddressSanitizer" -> "AddressSanitizerFunction"
+            "AggressiveDeadCodeElimination" -> "AggressiveDCE"
+            "AlwaysInline" -> "AlwaysInliner"
+            "DeadInstructionElimination" -> "DeadInstElimination"
+            "EarlyCommonSubexpressionElimination" -> "EarlyCSE"
+            "FunctionAttributes" -> "FunctionAttrs"
+            "GlobalDeadCodeElimination" -> "GlobalDCE"
+            "InductionVariableSimplify" -> "IndVarSimplify"
+            "InternalizeFunctions" -> "Internalize"
+            "InterproceduralSparseConditionalConstantPropagation" -> "IPSCCP"
+            "LoopClosedSingleStaticAssignment" -> "LCSSA"
+            "LoopInvariantCodeMotion" -> "LICM"
+            "LoopInstructionSimplify" -> "LoopInstSimplify"
+            "MemcpyOptimization" -> "MemCpyOpt"
+            "PruneExceptionHandling" -> "PruneEH"
+            "ScalarReplacementOfAggregates" -> "SROA"
+            "OldScalarReplacementOfAggregates" -> "ScalarReplAggregates"
+            "SimplifyControlFlowGraph" -> "CFGSimplification"
+            "SparseConditionalConstantPropagation" -> "SCCP"
+            "SuperwordLevelParallelismVectorize" -> "SLPVectorize"
+            h -> h
+        patchImpls = [
+         "AddressSanitizer",
+         "AddressSanitizerModule",
+         "BoundsChecking",
+         "CodeGenPrepare",
+         "GlobalValueNumbering",
+         "InternalizeFunctions",
+         "BasicBlockVectorize",
+         "BlockPlacement",
+         "BreakCriticalEdges",
+         "DeadCodeElimination",
+         "DeadInstructionElimination",
+         "DemoteRegisterToMemory",
+         "EdgeProfiler",
+         "GCOVProfiler",
+         "LoopClosedSingleStaticAssignment",
+         "LoopInstructionSimplify",
+         "LoopStrengthReduce",
+         "LoopVectorize",
+         "LowerAtomic",
+         "LowerInvoke",
+         "LowerSwitch",
+         "MemorySanitizer",
+         "MergeFunctions",
+         "OptimalEdgeProfiler",
+         "PathProfiler",
+         "PartialInlining",
+         "ScalarReplacementOfAggregates",
+         "Sinking",
+         "StripDeadDebugInfo",
+         "StripDebugDeclare",
+         "StripNonDebugSymbols",
+         "ThreadSanitizer"
+         ]
+    in
+      (if (n `elem` patchImpls) then "LLVM_Hs_" else "LLVM") ++ "Add" ++ core ++ "Pass"
diff --git a/src/LLVM/Internal/FFI/Type.h b/src/LLVM/Internal/FFI/Type.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Type.h
@@ -0,0 +1,23 @@
+#ifndef __LLVM_INTERNAL_FFI__TYPE__H__
+#define __LLVM_INTERNAL_FFI__TYPE__H__
+
+#define LLVM_HS_FOR_EACH_TYPE_KIND(macro) \
+	macro(Void) \
+	macro(Half) \
+	macro(Float) \
+	macro(Double) \
+	macro(X86_FP80) \
+	macro(FP128) \
+	macro(PPC_FP128) \
+	macro(Label) \
+	macro(Integer) \
+	macro(Function) \
+	macro(Struct) \
+	macro(Array) \
+	macro(Pointer) \
+	macro(Vector) \
+	macro(Metadata) \
+	macro(X86_MMX) \
+	macro(Token)
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Type.hs b/src/LLVM/Internal/FFI/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Type.hs
@@ -0,0 +1,160 @@
+{-# LANGUAGE
+  ForeignFunctionInterface
+  #-}
+-- | Functions for handling the LLVM types
+module LLVM.Internal.FFI.Type where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.Context
+import LLVM.Internal.FFI.PtrHierarchy
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreType.html#ga112756467f0988613faa6043d674d843>
+foreign import ccall unsafe "LLVMGetTypeKind" getTypeKind ::
+  Ptr Type -> IO TypeKind
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeInt.html#gadfb8ba2f605f0860a4bf2e3c480ab6a2>
+foreign import ccall unsafe "LLVMGetIntTypeWidth" getIntTypeWidth ::
+  Ptr Type -> IO (CUInt)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFunction.html#ga2970f0f4d9ee8a0f811f762fb2fa7f82>
+foreign import ccall unsafe "LLVMIsFunctionVarArg" isFunctionVarArg ::
+  Ptr Type -> IO LLVMBool
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFunction.html#gacfa4594cbff421733add602a413cae9f>
+foreign import ccall unsafe "LLVMGetReturnType" getReturnType ::
+  Ptr Type -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFunction.html#ga44fa41d22ed1f589b8202272f54aad77>
+foreign import ccall unsafe "LLVMCountParamTypes" countParamTypes ::
+  Ptr Type -> IO CUInt
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFunction.html#ga83dd3a49a0f3f017f4233fc0d667bda2>
+foreign import ccall unsafe "LLVMGetParamTypes" getParamTypes ::
+  Ptr Type -> Ptr (Ptr Type) -> IO ()
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#ga0b03e26a2d254530a9b5c279cdf52257>
+foreign import ccall unsafe "LLVMGetElementType" getElementType ::
+  Ptr Type -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeInt.html#ga2e5db8cbc30daa156083f2c42989138d>
+foreign import ccall unsafe "LLVMIntTypeInContext" intTypeInContext ::
+  Ptr Context -> CUInt -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFunction.html#ga8b0c32e7322e5c6c1bf7eb95b0961707>
+foreign import ccall unsafe "LLVMFunctionType" functionType' ::
+  Ptr Type -> Ptr (Ptr Type) -> CUInt -> LLVMBool -> IO (Ptr Type)
+
+functionType :: Ptr Type -> (CUInt, Ptr (Ptr Type)) -> LLVMBool -> IO (Ptr Type)
+functionType rt (n, ats) va = functionType' rt ats n va
+
+newtype AddrSpace = AddrSpace CUInt
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#ga299fe6147083678d0494b1b875f542fae>
+foreign import ccall unsafe "LLVMPointerType" pointerType ::
+  Ptr Type -> AddrSpace -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#ga124b162b69b5def41dde2fda3668cbd9>
+foreign import ccall unsafe "LLVMGetPointerAddressSpace" getPointerAddressSpace ::
+  Ptr Type -> IO AddrSpace
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#ga5ec731adf74fb40bc3b401956d0c6ff2>
+foreign import ccall unsafe "LLVMVectorType" vectorType ::
+  Ptr Type -> CUInt -> IO (Ptr Type)
+
+-- | what <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#gabd1666e080f693e1af0b4018005cd927>
+-- | would be if it supported 64-bit array sizes, as the C++ type does.
+foreign import ccall unsafe "LLVM_Hs_ArrayType" arrayType ::
+  Ptr Type -> Word64 -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#gaff2af74740a22f7d18701f0d8c3e5a6f>
+foreign import ccall unsafe "LLVMStructTypeInContext" structTypeInContext' ::
+  Ptr Context -> Ptr (Ptr Type) -> CUInt -> LLVMBool -> IO (Ptr Type)
+
+structTypeInContext :: Ptr Context -> (CUInt, Ptr (Ptr Type)) -> LLVMBool -> IO (Ptr Type)
+structTypeInContext ctx (n, ts) p = structTypeInContext' ctx ts n p
+
+-- | The reason we don't just use <https://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#gaf3bed4d4b79664d613acf8b9dbfbccb7>
+-- | is because we LLVM may adjust the typename, and we need to capture the new name if that happens.
+foreign import ccall unsafe "LLVM_Hs_StructCreateNamed" structCreateNamed ::
+  Ptr Context -> CString -> Ptr (OwnerTransfered CString) -> IO (Ptr Type)
+
+foreign import ccall unsafe "LLVMGetStructName" getStructName ::
+  Ptr Type -> IO CString
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#gaf7a24fcfbf80b61b478cafe81fc25a43>
+foreign import ccall unsafe "LLVMIsLiteralStruct" structIsLiteral ::
+  Ptr Type -> IO LLVMBool
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#ga97ec8b94d2b1d055691b3a086dfcefea>
+foreign import ccall unsafe "LLVMIsOpaqueStruct" structIsOpaque ::
+  Ptr Type -> IO LLVMBool
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#ga3e940e660375ae0cbdde81c0d8ec91e3>
+foreign import ccall unsafe "LLVMIsPackedStruct" isPackedStruct ::
+  Ptr Type -> IO LLVMBool
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeStruct.html#gaf32e6d6bcec38b786efbef689b0dddf7>
+foreign import ccall unsafe "LLVMCountStructElementTypes" countStructElementTypes ::
+  Ptr Type -> IO CUInt
+
+foreign import ccall unsafe "LLVMGetStructElementTypes" getStructElementTypes ::
+  Ptr Type -> Ptr (Ptr Type) -> IO ()
+
+foreign import ccall unsafe "LLVMStructSetBody" structSetBody' ::
+  Ptr Type -> Ptr (Ptr Type) -> CUInt -> LLVMBool -> IO ()
+
+structSetBody :: Ptr Type -> (CUInt, Ptr (Ptr Type)) -> LLVMBool -> IO ()
+structSetBody s (n,ts) p = structSetBody' s ts n p
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#gafb88a5ebd2a8062e105854910dc7ca17>
+foreign import ccall unsafe "LLVMGetVectorSize" getVectorSize ::
+  Ptr Type -> IO CUInt
+
+-- | what <http://llvm.org/doxygen/group__LLVMCCoreTypeSequential.html#ga02dc08041a12265cb700ee469497df63>
+-- | would be if it supported 64 bit lengths
+foreign import ccall unsafe "LLVM_Hs_GetArrayLength" getArrayLength ::
+  Ptr Type -> IO Word64
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeOther.html#ga1c78ca6d7bf279330b9195fa52f23828>
+foreign import ccall unsafe "LLVMVoidTypeInContext" voidTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#ga3a5332a1d075602bccad7576d1a8e36f>
+foreign import ccall unsafe "LLVMHalfTypeInContext" halfTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#ga529c83a8a5461e5beac19eb867216e3c>
+foreign import ccall unsafe "LLVMFloatTypeInContext" floatTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#ga200527010747eab31b73d3e3f6d94935>
+foreign import ccall unsafe "LLVMDoubleTypeInContext" doubleTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#ga24f77b84b625ed3dd516b52480606093>
+foreign import ccall unsafe "LLVMX86FP80TypeInContext" x86FP80TypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#ga1c02fb08f9ae12a719ed42099d42ccd8>
+foreign import ccall unsafe "LLVMFP128TypeInContext" fP128TypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeFloat.html#gac2491184fc3d8631c7b264c067f2f761>
+foreign import ccall unsafe "LLVMPPCFP128TypeInContext" ppcFP128TypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreTypeOther.html#ga59283de371ba6d44a2e2c8bd0db108e8>
+foreign import ccall unsafe "LLVMMetadataTypeInContext" metadataTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <https://llvm.org/doxygen/group__LLVMCCoreTypeOther.html#ga5d3702e198e2373db7e31bb18879efc3>
+foreign import ccall unsafe "LLVMTokenTypeInContext" tokenTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreTypeOther.html#ga7b7c56bf8406c50205fdd410b351ad81>
+foreign import ccall unsafe "LLVMLabelTypeInContext" labelTypeInContext ::
+  Ptr Context -> IO (Ptr Type)
diff --git a/src/LLVM/Internal/FFI/TypeC.cpp b/src/LLVM/Internal/FFI/TypeC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/TypeC.cpp
@@ -0,0 +1,31 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm-c/Core.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
+
+using namespace llvm;
+
+extern "C" {
+
+// LLVM may rename the type, which we must capture.
+LLVMTypeRef LLVM_Hs_StructCreateNamed(LLVMContextRef C, const char *Name, char** renamedName) {
+    if (Name) {
+        auto t = StructType::create(*unwrap(C), Name);
+        *renamedName = strdup(t->getName().str().c_str());
+        return wrap(t);
+    } else {
+        *renamedName = nullptr;
+        return wrap(StructType::create(*unwrap(C)));
+    }
+}
+
+LLVMTypeRef LLVM_Hs_ArrayType(LLVMTypeRef ElementType, uint64_t ElementCount) {
+    return wrap(ArrayType::get(unwrap(ElementType), ElementCount));
+}
+
+uint64_t LLVM_Hs_GetArrayLength(LLVMTypeRef ArrayTy) {
+    return unwrap<ArrayType>(ArrayTy)->getNumElements();
+}
+
+}
diff --git a/src/LLVM/Internal/FFI/User.hs b/src/LLVM/Internal/FFI/User.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/User.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM User class
+module LLVM.Internal.FFI.User where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.PtrHierarchy
+
+-- | a blind type to correspond to llvm::Use
+data Use
+
+-- | test if a 'Value' is a 'User'
+foreign import ccall unsafe "LLVMIsAUser" isAUser ::
+    Ptr Value -> IO (Ptr User)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueUses.html#ga66a226d3d06ffada5c929656f4d97d35>
+foreign import ccall unsafe "LLVMGetFirstUse" getFirstUse ::
+    Ptr User -> IO (Ptr Use)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueUses.html#ga6ea72661bcca2b77bea57173317ec942>
+foreign import ccall unsafe "LLVMGetNextUse" getNextUse ::
+    Ptr Use -> IO (Ptr Use)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueUser.html#ga2ad633a6afc7906f1afe329f244240f6>
+foreign import ccall unsafe "LLVMGetNumOperands" getNumOperands ::
+    Ptr User -> IO CUInt
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueUser.html#ga799d58a361054323cb457945071cbfdb>
+foreign import ccall unsafe "LLVMGetOperand" getOperand ::
+    Ptr User -> CUInt -> IO (Ptr Value)
+
diff --git a/src/LLVM/Internal/FFI/Value.h b/src/LLVM/Internal/FFI/Value.h
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Value.h
@@ -0,0 +1,32 @@
+#ifndef __LLVM_INTERNAL_FFI__VALUE__H__
+#define __LLVM_INTERNAL_FFI__VALUE__H__
+
+#define LLVM_HS_FOR_EACH_VALUE_SUBCLASS(macro) \
+	macro(Argument) \
+	macro(BasicBlock) \
+	macro(Function) \
+	macro(GlobalAlias) \
+	macro(GlobalVariable) \
+	macro(UndefValue) \
+	macro(BlockAddress) \
+	macro(ConstantExpr) \
+	macro(ConstantAggregateZero) \
+	macro(ConstantDataArray) \
+	macro(ConstantDataVector) \
+	macro(ConstantInt) \
+	macro(ConstantFP) \
+	macro(ConstantArray) \
+	macro(ConstantStruct) \
+	macro(ConstantTokenNone) \
+	macro(ConstantVector) \
+	macro(ConstantPointerNull) \
+	macro(InlineAsm) \
+	macro(Instruction)
+
+typedef enum {
+#define ENUM_CASE(class) LLVM ## class ## SubclassId,
+LLVM_HS_FOR_EACH_VALUE_SUBCLASS(ENUM_CASE)
+#undef ENUM_CASE
+} LLVMValueSubclassId;
+
+#endif
diff --git a/src/LLVM/Internal/FFI/Value.hs b/src/LLVM/Internal/FFI/Value.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/Value.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE
+  ForeignFunctionInterface,
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+-- | FFI functions for handling the LLVM Value class
+module LLVM.Internal.FFI.Value where
+
+import LLVM.Prelude
+
+import Foreign.Ptr
+import Foreign.C
+
+import LLVM.Internal.FFI.LLVMCTypes
+import LLVM.Internal.FFI.PtrHierarchy
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueGeneral.html#ga12179f46b79de8436852a4189d4451e0>
+foreign import ccall unsafe "LLVMTypeOf" typeOf ::
+  Ptr Value -> IO (Ptr Type)
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueGeneral.html#ga70948786725c43968d15225dd584e5a9>
+foreign import ccall unsafe "LLVMGetValueName" getValueName ::
+  Ptr Value -> IO CString
+
+-- | <http://llvm.org/doxygen/group__LLVMCCoreValueGeneral.html#gac1f61f74d83d218d4943c018e8fd8d13>
+foreign import ccall unsafe "LLVMSetValueName" setValueName ::
+  Ptr Value -> CString -> IO ()
+
+-- | This function exposes the ID returned by llvm::Value::getValueID()
+-- | <http://llvm.org/doxygen/classllvm_1_1Value.html#a2983b7b4998ef5b9f51b18c01588af3c>. 
+foreign import ccall unsafe "LLVM_Hs_GetValueSubclassId" getValueSubclassId ::
+  Ptr Value -> IO ValueSubclassId
+
+foreign import ccall unsafe "LLVMReplaceAllUsesWith" replaceAllUsesWith ::
+  Ptr Value -> Ptr Value -> IO ()
+
+foreign import ccall unsafe "LLVM_Hs_CreateArgument" createArgument ::
+  Ptr Type -> CString -> IO (Ptr Value)
+
+foreign import ccall unsafe "LLVMDumpValue" dumpValue ::
+  Ptr Value -> IO ()
diff --git a/src/LLVM/Internal/FFI/ValueC.cpp b/src/LLVM/Internal/FFI/ValueC.cpp
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FFI/ValueC.cpp
@@ -0,0 +1,30 @@
+#define __STDC_LIMIT_MACROS
+#include "llvm-c/Core.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/Argument.h"
+#include "LLVM/Internal/FFI/Value.h"
+
+using namespace llvm;
+
+extern "C" {
+
+LLVMValueSubclassId LLVM_Hs_GetValueSubclassId(LLVMValueRef v) {
+	switch(unwrap(v)->getValueID()) {
+#define VALUE_SUBCLASS_ID_CASE(class) case Value::class ## Val: return LLVM ## class ## SubclassId;
+LLVM_HS_FOR_EACH_VALUE_SUBCLASS(VALUE_SUBCLASS_ID_CASE)
+#undef VALUE_SUBCLASS_ID_CASE
+	default: break;
+	}
+	return LLVMValueSubclassId(0);
+}
+
+LLVMValueRef LLVM_Hs_CreateArgument(
+	LLVMTypeRef t,
+	const char *name
+) {
+	return wrap(new Argument(unwrap(t), name));
+}
+
+}
diff --git a/src/LLVM/Internal/FastMathFlags.hs b/src/LLVM/Internal/FastMathFlags.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FastMathFlags.hs
@@ -0,0 +1,53 @@
+{-# LANGUAGE 
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.FastMathFlags where
+
+import LLVM.Prelude
+
+import Control.Monad.Trans
+import Control.Monad.AnyCont
+import Control.Monad.State
+import Control.Exception
+
+import Data.Bits
+
+import qualified LLVM.Internal.FFI.Builder as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.EncodeAST
+
+import qualified LLVM.AST as A
+
+instance EncodeM IO A.FastMathFlags FFI.FastMathFlags where
+  encodeM f = return $ foldr1 (.|.) [
+               if a f then b else 0
+               | (a,b) <- [
+                (A.allowReassoc, FFI.fastMathFlagsAllowReassoc),
+                (A.noNaNs, FFI.fastMathFlagsNoNaNs),
+                (A.noInfs, FFI.fastMathFlagsNoInfs),
+                (A.noSignedZeros, FFI.fastMathFlagsNoSignedZeros),
+                (A.allowReciprocal, FFI.fastMathFlagsAllowReciprocal),
+                (A.allowContract, FFI.fastMathFlagsAllowContract),
+                (A.approxFunc, FFI.fastMathFlagsApproxFunc)
+               ] 
+              ]
+
+instance EncodeM EncodeAST A.FastMathFlags () where
+  encodeM f = do 
+    f <- liftIO $ encodeM f
+    builder <- gets encodeStateBuilder
+    anyContToM $ bracket (FFI.setFastMathFlags builder f) (\() -> FFI.setFastMathFlags builder 0)
+
+instance Monad m => DecodeM m A.FastMathFlags FFI.FastMathFlags where
+  decodeM f = return A.FastMathFlags {
+                A.allowReassoc = FFI.fastMathFlagsAllowReassoc .&. f /= 0,
+                A.noNaNs = FFI.fastMathFlagsNoNaNs .&. f /= 0,
+                A.noInfs = FFI.fastMathFlagsNoInfs .&. f /= 0,
+                A.noSignedZeros = FFI.fastMathFlagsNoSignedZeros .&. f /= 0,
+                A.allowReciprocal = FFI.fastMathFlagsAllowReciprocal .&. f /= 0,
+                A.allowContract = FFI.fastMathFlagsAllowContract .&. f /= 0,
+                A.approxFunc = FFI.fastMathFlagsApproxFunc .&. f /= 0
+              }
+
diff --git a/src/LLVM/Internal/FloatingPointPredicate.hs b/src/LLVM/Internal/FloatingPointPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/FloatingPointPredicate.hs
@@ -0,0 +1,29 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  TemplateHaskell
+  #-}
+module LLVM.Internal.FloatingPointPredicate where
+
+import LLVM.Internal.Coding
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.AST.FloatingPointPredicate as A.FPPred
+
+genCodingInstance [t| A.FPPred.FloatingPointPredicate |] ''FFI.FCmpPredicate [
+  (FFI.fCmpPredFalse, A.FPPred.False),
+  (FFI.fCmpPredOEQ, A.FPPred.OEQ),
+  (FFI.fCmpPredOGT, A.FPPred.OGT),
+  (FFI.fCmpPredOGE, A.FPPred.OGE),
+  (FFI.fCmpPredOLT, A.FPPred.OLT),
+  (FFI.fCmpPredOLE, A.FPPred.OLE),
+  (FFI.fCmpPredONE, A.FPPred.ONE),
+  (FFI.fCmpPredORD, A.FPPred.ORD),
+  (FFI.fCmpPredUNO, A.FPPred.UNO),
+  (FFI.fCmpPredUEQ, A.FPPred.UEQ),
+  (FFI.fCmpPredUGT, A.FPPred.UGT),
+  (FFI.fCmpPredUGE, A.FPPred.UGE),
+  (FFI.fCmpPredULT, A.FPPred.ULT),
+  (FFI.fCmpPredULE, A.FPPred.ULE),
+  (FFI.fCmpPredUNE, A.FPPred.UNE),
+  (FFI.fcmpPredTrue, A.FPPred.True)
+ ]
diff --git a/src/LLVM/Internal/Function.hs b/src/LLVM/Internal/Function.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Function.hs
@@ -0,0 +1,68 @@
+module LLVM.Internal.Function where
+
+import LLVM.Prelude
+
+import Control.Monad.Trans
+import Control.Monad.AnyCont
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.Function as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Attribute as FFI
+
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.Value
+import LLVM.Internal.Coding
+import LLVM.Internal.Constant ()
+import LLVM.Internal.Attribute
+
+import qualified LLVM.AST as A
+import qualified LLVM.AST.Constant as A
+import qualified LLVM.AST.ParameterAttribute as A.PA
+
+getAttributeList :: Ptr FFI.Function -> DecodeAST AttributeList
+getAttributeList f = do
+  decodeM (FFI.AttrSetDecoder FFI.attributesAtIndex FFI.countParams, f)
+
+setFunctionAttributes :: Ptr FFI.Function -> AttributeList -> EncodeAST ()
+setFunctionAttributes f = liftIO . FFI.setAttributeList f <=< encodeM
+
+getParameters :: Ptr FFI.Function -> [[A.PA.ParameterAttribute]] -> DecodeAST [A.Parameter]
+getParameters f attrs = scopeAnyCont $ do
+  n <- liftIO (FFI.countParams f)
+  ps <- allocaArray n
+  liftIO $ FFI.getParams f ps
+  params <- peekArray n ps
+  forM (leftBiasedZip params attrs) $ \(param, pAttrs) ->
+    A.Parameter
+      <$> typeOf param
+      <*> getLocalName param
+      <*> (return $ fromMaybe [] pAttrs)
+  
+getGC :: Ptr FFI.Function -> DecodeAST (Maybe ShortByteString)
+getGC f = scopeAnyCont $ decodeM =<< liftIO (FFI.getGC f)
+
+setGC :: Ptr FFI.Function -> Maybe ShortByteString -> EncodeAST ()
+setGC f gc = scopeAnyCont $ liftIO . FFI.setGC f =<< encodeM gc 
+
+getPrefixData :: Ptr FFI.Function -> DecodeAST (Maybe A.Constant)
+getPrefixData f = do
+  has <- decodeM =<< (liftIO $ FFI.hasPrefixData f)
+  if has
+   then decodeM =<< (liftIO $ FFI.getPrefixData f)
+   else return Nothing
+
+setPrefixData :: Ptr FFI.Function -> Maybe A.Constant -> EncodeAST ()
+setPrefixData f = traverse_ (liftIO . FFI.setPrefixData f <=< encodeM)
+
+getPersonalityFn :: Ptr FFI.Function -> DecodeAST (Maybe A.Constant)
+getPersonalityFn f = do
+  has <- decodeM =<< liftIO (FFI.hasPersonalityFn f)
+  if has
+     then decodeM =<< liftIO (FFI.getPersonalityFn f)
+     else pure Nothing
+
+setPersonalityFn :: Ptr FFI.Function -> Maybe A.Constant -> EncodeAST ()
+setPersonalityFn f personality = (liftIO . FFI.setPersonalityFn f =<< encodeM personality)
diff --git a/src/LLVM/Internal/Global.hs b/src/LLVM/Internal/Global.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Global.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses,
+  OverloadedStrings
+  #-}
+module LLVM.Internal.Global where
+
+import LLVM.Prelude
+
+import Control.Monad.State
+import Control.Monad.AnyCont
+import Foreign.Ptr
+import qualified Data.Map as Map
+
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.GlobalValue as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+
+import qualified LLVM.AST.Linkage as A.L
+import qualified LLVM.AST.Visibility as A.V
+import qualified LLVM.AST.COMDAT as A.COMDAT
+import qualified LLVM.AST.DLL as A.DLL
+import qualified LLVM.AST.ThreadLocalStorage as A.TLS
+import qualified LLVM.AST.Global as A.G
+
+genCodingInstance [t| A.L.Linkage |] ''FFI.Linkage [
+  (FFI.linkageExternal, A.L.External),
+  (FFI.linkageAvailableExternally, A.L.AvailableExternally),
+  (FFI.linkageLinkOnceAny, A.L.LinkOnce),
+  (FFI.linkageLinkOnceODR, A.L.LinkOnceODR),
+  (FFI.linkageWeakAny, A.L.Weak),
+  (FFI.linkageWeakODR, A.L.WeakODR),
+  (FFI.linkageAppending, A.L.Appending),
+  (FFI.linkageInternal, A.L.Internal),
+  (FFI.linkagePrivate, A.L.Private),
+  (FFI.linkageExternalWeak, A.L.ExternWeak),
+  (FFI.linkageCommon, A.L.Common)
+ ]
+
+getLinkage :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST A.L.Linkage
+getLinkage g = liftIO $ decodeM =<< FFI.getLinkage (FFI.upCast g)
+
+setLinkage :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> A.L.Linkage -> EncodeAST ()
+setLinkage g l = liftIO . FFI.setLinkage (FFI.upCast g) =<< encodeM l
+                                                                       
+genCodingInstance [t| A.V.Visibility |] ''FFI.Visibility [
+  (FFI.visibilityDefault, A.V.Default),
+  (FFI.visibilityHidden, A.V.Hidden),
+  (FFI.visibilityProtected, A.V.Protected)
+ ]
+
+getVisibility :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST A.V.Visibility
+getVisibility g = liftIO $ decodeM =<< FFI.getVisibility (FFI.upCast g)
+
+setVisibility :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> A.V.Visibility -> EncodeAST ()
+setVisibility g v = liftIO . FFI.setVisibility (FFI.upCast g) =<< encodeM v
+
+genCodingInstance [t| Maybe A.DLL.StorageClass |] ''FFI.DLLStorageClass [
+  (FFI.dllStorageClassDefault, Nothing),
+  (FFI.dllStorageClassDLLImport, Just A.DLL.Import),
+  (FFI.dllStorageClassDLLExport, Just A.DLL.Export)
+ ]
+
+getDLLStorageClass :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST (Maybe A.DLL.StorageClass)
+getDLLStorageClass g = liftIO $ decodeM =<< FFI.getDLLStorageClass (FFI.upCast g)
+
+setDLLStorageClass :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> Maybe A.DLL.StorageClass -> EncodeAST ()
+setDLLStorageClass g sc = liftIO . FFI.setDLLStorageClass (FFI.upCast g) =<< encodeM sc
+
+getSection :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST (Maybe ShortByteString)
+getSection g = do
+  sectionLengthPtr <- alloca
+  sectionNamePtr <- liftIO $ FFI.getSection (FFI.upCast g) sectionLengthPtr
+  if sectionNamePtr == nullPtr then
+    return Nothing
+    else
+      do sectionLength <- peek sectionLengthPtr
+         sectionName <- decodeM (sectionNamePtr, sectionLength)
+         return (Just sectionName)
+
+setSection :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> Maybe ShortByteString -> EncodeAST ()
+setSection g s = scopeAnyCont $ do
+  s <- encodeM (fromMaybe "" s)
+  liftIO $ FFI.setSection (FFI.upCast g) s
+
+genCodingInstance [t| A.COMDAT.SelectionKind |] ''FFI.COMDATSelectionKind [
+  (FFI.comdatSelectionKindAny, A.COMDAT.Any),
+  (FFI.comdatSelectionKindExactMatch, A.COMDAT.ExactMatch),
+  (FFI.comdatSelectionKindLargest, A.COMDAT.Largest),
+  (FFI.comdatSelectionKindNoDuplicates, A.COMDAT.NoDuplicates),
+  (FFI.comdatSelectionKindSameSize, A.COMDAT.SameSize)
+ ]
+
+instance DecodeM DecodeAST (ShortByteString, A.COMDAT.SelectionKind) (Ptr FFI.COMDAT) where
+  decodeM c =
+    (,)
+      <$> decodeM (FFI.getCOMDATName c)
+      <*> (decodeM =<< liftIO (FFI.getCOMDATSelectionKind c))
+
+getCOMDATName :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST (Maybe ShortByteString)
+getCOMDATName g = do
+  c <- liftIO $ FFI.getCOMDAT (FFI.upCast g)
+  if c == nullPtr
+   then return Nothing
+   else do
+     cds <- gets comdats
+     liftM Just $ case Map.lookup c cds of
+       Just (name, _) -> return name
+       Nothing -> do
+          cd@(name, _) <- decodeM c
+          modify $ \s -> s { comdats = Map.insert c cd cds }
+          return name
+
+setCOMDAT :: FFI.DescendentOf FFI.GlobalObject v => Ptr v -> Maybe ShortByteString -> EncodeAST ()
+setCOMDAT _ Nothing = return ()
+setCOMDAT g (Just name) = do
+  cd <- referCOMDAT name
+  liftIO $ FFI.setCOMDAT (FFI.upCast g) cd
+
+setAlignment :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> Word32 -> EncodeAST ()
+setAlignment g i = liftIO $ FFI.setAlignment (FFI.upCast g) (fromIntegral i)
+
+getAlignment :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST Word32
+getAlignment g = liftIO $ fromIntegral <$> FFI.getAlignment (FFI.upCast g)
+
+genCodingInstance [t| Maybe A.TLS.Model |] ''FFI.ThreadLocalMode [
+  (FFI.threadLocalModeNotThreadLocal, Nothing),
+  (FFI.threadLocalModeGeneralDynamicTLSModel, Just A.TLS.GeneralDynamic),
+  (FFI.threadLocalModeLocalDynamicTLSModel, Just A.TLS.LocalDynamic),
+  (FFI.threadLocalModeInitialExecTLSModel, Just A.TLS.InitialExec),
+  (FFI.threadLocalModeLocalExecTLSModel, Just A.TLS.LocalExec)
+ ]
+
+getThreadLocalMode :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> DecodeAST (Maybe A.TLS.Model)
+getThreadLocalMode g = liftIO $ decodeM =<< FFI.getThreadLocalMode (FFI.upCast g)
+
+setThreadLocalMode :: FFI.DescendentOf FFI.GlobalValue v => Ptr v -> Maybe A.TLS.Model -> EncodeAST ()
+setThreadLocalMode g m = liftIO . FFI.setThreadLocalMode (FFI.upCast g) =<< encodeM m
+
+genCodingInstance [t| Maybe A.G.UnnamedAddr |] ''FFI.UnnamedAddr [
+  (FFI.unnamedAddrNo, Nothing),
+  (FFI.unnamedAddrLocal, Just A.G.LocalAddr),
+  (FFI.unnamedAddrGlobal, Just A.G.GlobalAddr)
+ ]
diff --git a/src/LLVM/Internal/InlineAssembly.hs b/src/LLVM/Internal/InlineAssembly.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/InlineAssembly.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses,
+  OverloadedStrings
+  #-}
+module LLVM.Internal.InlineAssembly where
+ 
+import LLVM.Prelude
+
+import Control.Monad.IO.Class
+
+import qualified Data.ByteString.Char8 as ByteString
+
+import Foreign.C
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.InlineAssembly as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.Module as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+
+import qualified LLVM.AST as A (Definition(..))
+import qualified LLVM.AST.InlineAssembly as A
+import qualified LLVM.AST.Type as A
+
+import LLVM.Internal.Coding 
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.Value
+
+genCodingInstance [t| A.Dialect |] ''FFI.AsmDialect [
+   (FFI.asmDialectATT, A.ATTDialect),
+   (FFI.asmDialectIntel, A.IntelDialect)
+  ]
+
+instance EncodeM EncodeAST A.InlineAssembly (Ptr FFI.InlineAsm) where
+  encodeM (A.InlineAssembly {
+             A.type' = t,
+             A.assembly = assembly,
+             A.constraints = constraints,
+             A.hasSideEffects = hasSideEffects,
+             A.alignStack = alignStack,
+             A.dialect = dialect
+           }) = do
+    t <- encodeM t
+    assembly <- encodeM assembly
+    constraints <- encodeM constraints
+    hasSideEffects <- encodeM hasSideEffects
+    alignStack <- encodeM alignStack
+    dialect <- encodeM dialect
+    liftIO $ FFI.createInlineAsm t assembly constraints hasSideEffects alignStack dialect
+
+instance DecodeM DecodeAST A.InlineAssembly (Ptr FFI.InlineAsm) where
+  decodeM p = do
+    return A.InlineAssembly
+      `ap` (liftM (\(A.PointerType f _) -> f) (typeOf p))
+      `ap` (decodeM =<< liftIO (FFI.getInlineAsmAssemblyString p))
+      `ap` (decodeM =<< liftIO (FFI.getInlineAsmConstraintString p))
+      `ap` (decodeM =<< liftIO (FFI.inlineAsmHasSideEffects p))
+      `ap` (decodeM =<< liftIO (FFI.inlineAsmIsAlignStack p))
+      `ap` (decodeM =<< liftIO (FFI.getInlineAsmDialect p))
+
+instance DecodeM DecodeAST [A.Definition] (FFI.ModuleAsm CString) where
+  decodeM (FFI.ModuleAsm s) = do
+    s' <- decodeM s
+    return . map A.ModuleInlineAssembly $ ByteString.lines s'
diff --git a/src/LLVM/Internal/Instruction.hs b/src/LLVM/Internal/Instruction.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Instruction.hs
@@ -0,0 +1,653 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  QuasiQuotes,
+  MultiParamTypeClasses,
+  UndecidableInstances,
+  ViewPatterns
+  #-}
+module LLVM.Internal.Instruction where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+import qualified Language.Haskell.TH.Quote as TH
+import qualified LLVM.Internal.InstructionDefs as ID
+import LLVM.Internal.InstructionDefs (instrP)
+
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+import Control.Monad.State (gets)
+
+import Foreign.Ptr
+
+import Control.Exception (assert)
+import Control.Monad.Catch
+import qualified Data.Map as Map
+import qualified Data.List as List
+import Data.List.NonEmpty (NonEmpty((:|)))
+import qualified Data.List.NonEmpty as NonEmpty
+
+import qualified LLVM.Internal.FFI.Attribute as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.BinaryOperator as FFI
+import qualified LLVM.Internal.FFI.Instruction as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+import qualified LLVM.Internal.FFI.User as FFI
+import qualified LLVM.Internal.FFI.Builder as FFI
+import qualified LLVM.Internal.FFI.BasicBlock as FFI
+
+import LLVM.Internal.Atomicity ()
+import LLVM.Internal.Attribute
+import LLVM.Internal.CallingConvention ()
+import LLVM.Internal.Coding
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.FastMathFlags ()
+import LLVM.Internal.Metadata ()
+import LLVM.Internal.Operand ()
+import LLVM.Internal.RMWOperation ()
+import LLVM.Internal.TailCallKind ()
+import LLVM.Internal.Type
+import LLVM.Internal.Value
+
+import qualified LLVM.AST as A
+import qualified LLVM.AST.Constant as A.C
+import LLVM.Exception
+
+callInstAttributeList :: Ptr FFI.Instruction -> DecodeAST AttributeList
+callInstAttributeList instr =
+  decodeM
+    ( FFI.AttrSetDecoder
+        FFI.getCallSiteAttributesAtIndex
+        FFI.getCallSiteNumArgOperands
+    , instr)
+
+meta :: Ptr FFI.Instruction -> DecodeAST A.InstructionMetadata
+meta i = do
+  let getMetadata n = scopeAnyCont $ do
+         ks <- allocaArray n
+         ps <- allocaArray n
+         n' <- liftIO $ FFI.getMetadata i ks ps n
+         if (n' > n)
+          then getMetadata n'
+          else return zip `ap` decodeM (n', ks) `ap` decodeM (n', ps)
+  getMetadata 4
+
+setMD :: Ptr FFI.Instruction -> A.InstructionMetadata -> EncodeAST ()
+setMD i md = forM_ md $ \(kindName, anode) -> do
+               kindID <- encodeM kindName
+               node <- encodeM anode
+               liftIO $ FFI.setMetadata i kindID node
+
+instance DecodeM DecodeAST A.Terminator (Ptr FFI.Instruction) where
+  decodeM i = scopeAnyCont $ do
+    n <- liftIO $ FFI.getInstructionDefOpcode i
+    nOps <- liftIO $ FFI.getNumOperands (FFI.upCast i)
+    md <- meta i
+    let op n = decodeM =<< (liftIO $ FFI.getOperand (FFI.upCast i) n)
+        successor n = decodeM =<< (liftIO $ FFI.isABasicBlock =<< FFI.getOperand (FFI.upCast i) n)
+    case n of
+      [instrP|Ret|] -> do
+        returnOperand' <- if nOps == 0 then return Nothing else Just <$> op 0
+        return $ A.Ret { A.returnOperand = returnOperand', A.metadata' = md }
+      [instrP|Br|] -> do
+        n <- liftIO $ FFI.getNumOperands (FFI.upCast i)
+        case n of
+          1 -> do
+             dest <- successor 0
+             return $ A.Br { A.dest = dest, A.metadata' = md }
+          3 -> do
+             condition <- op 0
+             falseDest <- successor 1
+             trueDest <- successor 2
+             return $ A.CondBr {
+               A.condition = condition,
+               A.falseDest = falseDest,
+               A.trueDest = trueDest,
+               A.metadata' = md
+             }
+          _ -> error "Branch instructions should always have 1 or 3 operands"
+      [instrP|Switch|] -> do
+        op0 <- op 0
+        dd <- successor 1
+        let nCases = (nOps - 2) `div` 2
+        values <- allocaArray nCases
+        dests <- allocaArray nCases
+        liftIO $ FFI.getSwitchCases i values dests
+        cases <- return zip `ap` peekArray nCases values `ap` peekArray nCases dests
+        dests <- forM cases $ \(c, d) -> return (,) `ap` decodeM c `ap` decodeM d
+        return A.Switch {
+          A.operand0' = op0,
+          A.defaultDest = dd,
+          A.dests = dests,
+          A.metadata' = md
+        }
+      [instrP|IndirectBr|] -> do
+        op0 <- op 0
+        let nDests = nOps - 1
+        dests <- allocaArray nDests
+        liftIO $ FFI.getIndirectBrDests i dests
+        dests <- decodeM (nDests, dests)
+        return A.IndirectBr {
+           A.operand0' = op0,
+           A.possibleDests = dests,
+           A.metadata' = md
+        }
+      [instrP|Invoke|] -> do
+        cc <- decodeM =<< liftIO (FFI.getCallSiteCallingConvention i)
+        attrs <- callInstAttributeList i
+        fv <- liftIO $ FFI.getCallSiteCalledValue i
+        f <- decodeM fv
+        let argIndices = if nOps >= 4 then [0 .. nOps - 4] else []
+        args <-
+          forM (leftBiasedZip argIndices (parameterAttributes attrs)) $ \(j, pAttrs) ->
+                  (, fromMaybe [] pAttrs) <$> op j
+        rd <- successor (nOps - 3)
+        ed <- successor (nOps - 2)
+        return A.Invoke {
+          A.callingConvention' = cc,
+          A.returnAttributes' = returnAttributes attrs,
+          A.function' = f,
+          A.arguments' = args,
+          A.functionAttributes' = functionAttributes attrs,
+          A.returnDest = rd,
+          A.exceptionDest = ed,
+          A.metadata' = md
+        }
+      [instrP|Resume|] -> do
+        op0 <- op 0
+        return A.Resume {
+          A.operand0' = op0,
+          A.metadata' = md
+        }
+      [instrP|Unreachable|] -> do
+        return A.Unreachable {
+          A.metadata' = md
+        }
+      [instrP|CleanupRet|] -> do
+        dest <- decodeM =<< liftIO (FFI.upCast <$> (FFI.getCleanupPad i) :: IO (Ptr FFI.Value))
+        unwindDest <- decodeM =<< liftIO (FFI.getUnwindDest i)
+        return A.CleanupRet {
+          A.cleanupPad = dest,
+          A.unwindDest = unwindDest,
+          A.metadata' = md
+        }
+      [instrP|CatchRet|] -> do
+        catchPad <- decodeM =<< liftIO (FFI.catchRetGetCatchPad i)
+        successor <- decodeM =<< liftIO (FFI.catchRetGetSuccessor i)
+        return A.CatchRet {
+          A.catchPad = catchPad,
+          A.successor = successor,
+          A.metadata' = md
+        }
+      [instrP|CatchSwitch|] -> do
+        parentPad' <- decodeM =<< liftIO (FFI.catchSwitchGetParentPad i)
+        numHandlers <- liftIO (FFI.catchSwitchGetNumHandlers i)
+        handlers <- assert (numHandlers > 0) $
+          forM (0 :| [1..numHandlers - 1]) $ decodeM <=< liftIO . FFI.catchSwitchGetHandler i
+        unwindDest <- decodeM =<< liftIO (FFI.catchSwitchGetUnwindDest i)
+        return A.CatchSwitch {
+          A.parentPad' = parentPad',
+          A.catchHandlers = handlers,
+          A.defaultUnwindDest = unwindDest,
+          A.metadata' = md
+        }
+      i -> error ("Unknown terminator instruction kind: " <> show i)
+
+instance EncodeM EncodeAST A.Terminator (Ptr FFI.Instruction) where
+  encodeM t = scopeAnyCont $ do
+    builder <- gets encodeStateBuilder
+    s <- encodeM ""
+    t' <- case t of
+      A.Ret { A.returnOperand = r } -> do
+        rv <- maybe (return nullPtr) encodeM r
+        FFI.upCast <$> do liftIO $ FFI.buildRet builder rv
+      A.Br { A.dest = d } -> do
+        db <- encodeM d
+        FFI.upCast <$> do liftIO $ FFI.buildBr builder db
+      A.CondBr { A.condition = c, A.trueDest = t, A.falseDest = f } -> do
+        cv <- encodeM c
+        tb <- encodeM t
+        fb <- encodeM f
+        FFI.upCast <$> do liftIO $ FFI.buildCondBr builder cv tb fb
+      A.Switch {
+        A.operand0' = op0,
+        A.defaultDest = dd,
+        A.dests = ds
+      } -> do
+        op0' <- encodeM op0
+        dd' <- encodeM dd
+        i <- liftIO $ FFI.buildSwitch builder op0' dd' (fromIntegral $ length ds)
+        forM_ ds $ \(v,d) -> do
+          v' <- encodeM v
+          d' <- encodeM d
+          liftIO $ FFI.addCase i v' d'
+        return $ FFI.upCast i
+      A.IndirectBr {
+        A.operand0' = op0,
+        A.possibleDests = dests
+      } -> do
+        op0' <- encodeM op0
+        i <- liftIO $ FFI.buildIndirectBr builder op0' (fromIntegral $ length dests)
+        forM_ dests $ \dest -> do
+          d <- encodeM dest
+          liftIO $ FFI.addDestination i d
+        return $ FFI.upCast i
+      A.Invoke {
+        A.callingConvention' = cc,
+        A.returnAttributes' = rAttrs,
+        A.function' = fun,
+        A.arguments' = args,
+        A.functionAttributes' = fAttrs,
+        A.returnDest = rd,
+        A.exceptionDest = ed
+      } -> do
+        fv <- encodeM fun
+        rb <- encodeM rd
+        eb <- encodeM ed
+        let (argvs, argAttrs) = unzip args
+        (n, argvs) <- encodeM argvs
+        i <- liftIO $ FFI.buildInvoke builder fv argvs n rb eb s
+        attrs <- encodeM $ AttributeList fAttrs rAttrs argAttrs
+        liftIO $ FFI.setCallSiteAttributeList i attrs
+        cc <- encodeM cc
+        liftIO $ FFI.setCallSiteCallingConvention i cc
+        return $ FFI.upCast i
+      A.Resume {
+        A.operand0' = op0
+      } -> do
+        op0' <- encodeM op0
+        i <- liftIO $ FFI.buildResume builder op0'
+        return $ FFI.upCast i
+      A.Unreachable {
+      } -> do
+        i <- liftIO $ FFI.buildUnreachable builder
+        return $ FFI.upCast i
+      A.CleanupRet {
+        A.cleanupPad = cleanupPad,
+        A.unwindDest = unwindDest
+      } -> do
+        cleanupPad' <- encodeM cleanupPad
+        unwindDest' <- encodeM unwindDest
+        liftIO $ FFI.buildCleanupRet builder cleanupPad' unwindDest'
+      A.CatchRet {
+        A.catchPad = catchPad,
+        A.successor = successor
+      } -> do
+        catchPad' <- encodeM catchPad
+        successor' <- encodeM successor
+        liftIO $ FFI.buildCatchRet builder catchPad' successor'
+      A.CatchSwitch {
+        A.parentPad' = parentPad,
+        A.catchHandlers = catchHandlers,
+        A.defaultUnwindDest = unwindDest
+      } -> do
+        parentPad' <- encodeM parentPad
+        unwindDest' <- encodeM unwindDest
+        let numHandlers = fromIntegral (NonEmpty.length catchHandlers)
+        i <- liftIO $ FFI.buildCatchSwitch builder parentPad' unwindDest' numHandlers
+        mapM_ (liftIO . FFI.catchSwitchAddHandler i <=< encodeM) catchHandlers
+        return i
+    setMD t' (A.metadata' t)
+    return t'
+
+$(do
+  let findInstrFields s = Map.findWithDefault (error $ "instruction missing from AST: " ++ show s) s
+                          ID.astInstructionRecs
+
+  [d|
+    instance DecodeM DecodeAST A.Instruction (Ptr FFI.Instruction) where
+      decodeM i = scopeAnyCont $ do
+        t <- typeOf i
+        nOps <- liftIO $ FFI.getNumOperands (FFI.upCast i)
+        let op n = decodeM =<< (liftIO $ FFI.getOperand (FFI.upCast i) n)
+            get_nsw b = liftIO $ decodeM =<< FFI.hasNoSignedWrap (FFI.upCast b)
+            get_nuw b = liftIO $ decodeM =<< FFI.hasNoUnsignedWrap (FFI.upCast b)
+            get_exact b = liftIO $ decodeM =<< FFI.isExact (FFI.upCast b)
+            get_fastMathFlags b = liftIO $ decodeM =<< FFI.getFastMathFlags (FFI.upCast b)
+
+        n <- liftIO $ FFI.getInstructionDefOpcode i
+        $(
+          let fieldDecoders :: String -> String -> ([String], TH.ExpQ)
+              fieldDecoders lrn s = case s of
+                "b" -> ([], [| liftIO $ FFI.isABinaryOperator (FFI.upCast i) |])
+                "nsw" -> (["b"], [| get_nsw $(TH.dyn "b") |])
+                "nuw" -> (["b"], [| get_nuw $(TH.dyn "b") |])
+                "exact" -> (["b"], [| get_exact $(TH.dyn "b") |])
+                "fastMathFlags" -> (["b"], [| get_fastMathFlags $(TH.dyn "b") |])
+                "operand0" -> ([], [| op 0 |])
+                "operand1" -> ([], [| op 1 |])
+                "address" -> ([], case lrn of "Store" -> [| op 1 |]; _ -> [| op 0 |])
+                "value" -> ([], case lrn of "Store" -> [| op 0 |]; _ -> [| op 1 |])
+                "expected" -> ([], [| op 1 |])
+                "replacement" -> ([], [| op 2 |])
+                "condition'" -> ([], [| op 0 |])
+                "trueValue" -> ([], [| op 1 |])
+                "falseValue" -> ([], [| op 2 |])
+                "argList" -> ([], [| op 0 |])
+                "vector" -> ([], [| op 0 |])
+                "element" -> ([], [| op 1 |])
+                "index" -> ([], case lrn of
+                                  "ExtractElement" -> [| op 1 |]
+                                  "InsertElement" -> [| op 2 |]
+                                  _ -> [|error "Index fields are only supported for 'ExtractElement' and 'InsertElement': " <> lrn|])
+                "mask" ->
+                  ([], [| do
+                          n <- liftIO $ FFI.getShuffleVectorMaskSize i
+                          a <- allocaArray n
+                          liftIO $ FFI.getShuffleVectorMask i n a
+                          decodeM (n, a) |])
+                "aggregate" -> ([], [| op 0 |])
+                "metadata" -> ([], [| meta i |])
+                "iPredicate" -> ([], [| decodeM =<< liftIO (FFI.getICmpPredicate i) |])
+                "fpPredicate" -> ([], [| decodeM =<< liftIO (FFI.getFCmpPredicate i) |])
+                "tailCallKind" -> ([], [| decodeM =<< liftIO (FFI.getTailCallKind i) |])
+                "callingConvention" -> ([], [| decodeM =<< liftIO (FFI.getCallSiteCallingConvention i) |])
+                "attrs" -> ([], [| callInstAttributeList i |])
+                "returnAttributes" -> (["attrs"], [| return $ returnAttributes $(TH.dyn "attrs") |])
+                "f" -> ([], [| liftIO $ FFI.getCallSiteCalledValue i |])
+                "function" -> (["f"], [| decodeM $(TH.dyn "f") |])
+                "arguments" -> ([], [| forM (leftBiasedZip [1..nOps-1] (parameterAttributes $(TH.dyn "attrs"))) $ \(j, pAttrs) ->
+                                         (\p -> (p, fromMaybe [] pAttrs)) <$> op (j - 1) |])
+                "clauses" ->
+                  ([], [|do
+                          nClauses <- liftIO $ FFI.getNumClauses i
+                          -- We need to convert nClauses to a signed
+                          -- value before subtracting
+                          forM [0..fromIntegral nClauses - (1 :: Int)] $ \j -> do
+                            v <- liftIO $ FFI.getClause i (fromIntegral j)
+                            c <- decodeM v
+                            t <- typeOf v
+                            return $ case t of { A.ArrayType _ _ -> A.Filter; _ -> A.Catch} $ c |])
+                "functionAttributes" -> (["attrs"], [| return $ functionAttributes $(TH.dyn "attrs") |])
+                "type'" -> ([], [| return t |])
+                "incomingValues" ->
+                    ([], [| do
+                            n <- liftIO $ FFI.countIncoming i
+                            forM [0..n-1] $ \m -> do
+                              iv <- decodeM =<< (liftIO $ FFI.getIncomingValue i m)
+                              ib <- decodeM =<< (liftIO $ FFI.getIncomingBlock i m)
+                              return (iv,ib) |])
+                "allocatedType" -> ([], [| decodeM =<< liftIO (FFI.getAllocatedType i) |])
+                "numElements" ->
+                    ([], [| do
+                            n <- decodeM =<< (liftIO $ FFI.getAllocaNumElements i)
+                            return $ case n of
+                              A.ConstantOperand (A.C.Int { A.C.integerValue = 1 }) -> Nothing
+                              _ -> Just n
+                              |])
+                "alignment" -> ([], [| decodeM =<< liftIO (FFI.getInstrAlignment i) |])
+                "maybeAtomicity" -> ([], [| decodeM =<< liftIO (FFI.getAtomicity i) |])
+                "atomicity" -> ([], [| decodeM =<< liftIO (FFI.getAtomicity i) |])
+                "volatile" -> ([], [| decodeM =<< liftIO (FFI.getVolatile i) |])
+                "inBounds" -> ([], [| decodeM =<< liftIO (FFI.getInBounds (FFI.upCast i)) |])
+                "failureMemoryOrdering" -> ([], [| decodeM =<< liftIO (FFI.getFailureAtomicOrdering i) |])
+                "indices" -> ([], [| mapM op [1..nOps-1] |])
+                "indices'" ->
+                  ([], [| do
+                          n <- liftIO $ FFI.countInstStructureIndices i
+                          a <- allocaArray n
+                          liftIO $ FFI.getInstStructureIndices i a
+                          decodeM (n, a) |])
+                "rmwOperation" -> ([], [| decodeM =<< liftIO (FFI.getAtomicRMWBinOp i) |])
+                "cleanup" -> ([], [| decodeM =<< liftIO (FFI.isCleanup i) |])
+                "parentPad" -> ([], [| decodeM =<< liftIO (FFI.getParentPad i) |])
+                "catchSwitch" -> ([], [| decodeM =<< liftIO (FFI.getParentPad i) |])
+                "args" -> ([], [| do numArgs <- liftIO (FFI.getNumArgOperands i)
+                                     if (numArgs == 0)
+                                       then return []
+                                       else forM [0..numArgs-1] $ \op ->
+                                              decodeM =<< liftIO (FFI.getArgOperand i op) |])
+                _ -> ([], [| error $ "unrecognized instruction field or dependency thereof: " ++ show s |])
+          in
+          TH.caseE [| n |] $
+            [ TH.match opcodeP (TH.normalB (TH.doE handlerBody)) []
+            | (lrn, iDef) <- Map.toList ID.instructionDefs,
+              ID.instructionKind iDef /= ID.Terminator,
+              let opcodeP = TH.dataToPatQ (const Nothing) (ID.cppOpcode iDef)
+                  handlerBody =
+                    let TH.RecC fullName fields = findInstrFields lrn
+                        (fieldNames,_,_) = unzip3 fields
+                        allNames ns = List.nub $ [ d | n <- ns, d <- allNames . fst . fieldDecoders lrn $ n ] ++ ns
+                    in
+                      [
+                       TH.bindS (TH.varP (TH.mkName n)) (snd . fieldDecoders lrn $ n)
+                       | n <- allNames . map TH.nameBase $ fieldNames
+                      ] ++ [
+                       TH.noBindS [|
+                        return $(TH.recConE
+                                 fullName
+                                 [ (f,) <$> (TH.varE . TH.mkName . TH.nameBase $ f) | f <- fieldNames ])
+                        |]
+                      ]
+            ] ++
+            [ TH.match TH.wildP (TH.normalB [| error ("Unknown instruction opcode: " <> show n) |]) [] ]
+         )
+
+    instance EncodeM EncodeAST A.Instruction (Ptr FFI.Instruction, EncodeAST ()) where
+      encodeM o = scopeAnyCont $ do
+        builder <- gets encodeStateBuilder
+        let return' i = return (FFI.upCast i, return ())
+        s <- encodeM ""
+        (inst, act) <- case o of
+          A.ICmp {
+            A.iPredicate = pred,
+            A.operand0 = op0,
+            A.operand1 = op1
+          } -> do
+            op0' <- encodeM op0
+            op1' <- encodeM op1
+            pred <- encodeM pred
+            i <- liftIO $ FFI.buildICmp builder pred op0' op1' s
+            return' i
+          A.FCmp {
+            A.fpPredicate = pred,
+            A.operand0 = op0,
+            A.operand1 = op1
+          } -> do
+            op0' <- encodeM op0
+            op1' <- encodeM op1
+            pred <- encodeM pred
+            i <- liftIO $ FFI.buildFCmp builder pred op0' op1' s
+            return' i
+          A.Phi { A.type' = t, A.incomingValues = ivs } -> do
+             t' <- encodeM t
+             i <- liftIO $ FFI.buildPhi builder t' s
+             return (
+               FFI.upCast i,
+               do
+                 let (ivs3, bs3) = unzip ivs
+                 ivs3' <- encodeM ivs3
+                 bs3' <- encodeM bs3
+                 liftIO $ FFI.addIncoming i ivs3' bs3'
+               )
+          A.Select { A.condition' = c, A.trueValue = t, A.falseValue = f } -> do
+            c' <- encodeM c
+            t' <- encodeM t
+            f' <- encodeM f
+            i <- liftIO $ FFI.buildSelect builder c' t' f' s
+            return' i
+          A.Freeze { A.operand0 = op0, A.type' = t } -> do
+            op0' <- encodeM op0
+            t' <- encodeM t
+            i <- liftIO $ FFI.buildFreeze builder op0' t'
+            return' i
+          A.Call {
+            A.tailCallKind = tck,
+            A.callingConvention = cc,
+            A.returnAttributes = rAttrs,
+            A.function = f,
+            A.arguments = args,
+            A.functionAttributes = fAttrs
+          } -> do
+            fv <- encodeM f
+            let (argvs, argAttrs) = unzip args
+            (n, argvs) <- encodeM argvs
+            i <- liftIO $ FFI.buildCall builder fv argvs n s
+            attrs <- encodeM $ AttributeList fAttrs rAttrs argAttrs
+            liftIO $ FFI.setCallSiteAttributeList i attrs
+            tck <- encodeM tck
+            liftIO $ FFI.setTailCallKind i tck
+            cc <- encodeM cc
+            liftIO $ FFI.setCallSiteCallingConvention i cc
+            return' i
+          A.VAArg { A.argList = al, A.type' = t } -> do
+            al' <- encodeM al
+            t' <- encodeM t
+            i <- liftIO $ FFI.buildVAArg builder al' t' s
+            return' i
+          A.ExtractElement { A.vector = v, A.index = idx } -> do
+            v' <- encodeM v
+            idx' <- encodeM idx
+            i <- liftIO $ FFI.buildExtractElement builder v' idx' s
+            return' i
+          A.InsertElement { A.vector = v, A.element = e, A.index = idx } -> do
+            v' <- encodeM v
+            e' <- encodeM e
+            idx' <- encodeM idx
+            i <- liftIO $ FFI.buildInsertElement builder v' e' idx' s
+            return' i
+          A.ShuffleVector { A.operand0 = o0, A.operand1 = o1, A.mask = mask } -> do
+            o0' <- encodeM o0
+            o1' <- encodeM o1
+            (sizeMask, mask') <- encodeM mask
+            i <- liftIO $ FFI.buildShuffleVector builder o0' o1' mask' sizeMask s
+            return' i
+          A.ExtractValue { A.aggregate = a, A.indices' = is } -> do
+            a' <- encodeM a
+            (n, is') <- encodeM is
+            i <- liftIO $ FFI.buildExtractValue builder a' is' n s
+            return' i
+          A.InsertValue { A.aggregate = a, A.element = e, A.indices' = is } -> do
+            a' <- encodeM a
+            e' <- encodeM e
+            (n, is') <- encodeM is
+            i <- liftIO $ FFI.buildInsertValue builder a' e' is' n s
+            return' i
+          A.LandingPad {
+            A.type' = t,
+            A.cleanup = cl,
+            A.clauses = cs
+          } -> do
+            t' <- encodeM t
+            i <- liftIO $ FFI.buildLandingPad builder t' (fromIntegral $ length cs) s
+            forM_ cs $ \c ->
+              case c of
+                A.Catch a -> do
+                  cn <- encodeM a
+                  isArray <- liftIO $ isArrayType =<< FFI.typeOf (FFI.upCast cn)
+                  when isArray $ throwM . EncodeException $ "Catch clause cannot take an array: " ++ show c
+                  liftIO $ FFI.addClause i cn
+                A.Filter a -> do
+                  cn <- encodeM a
+                  isArray <- liftIO $ isArrayType =<< FFI.typeOf (FFI.upCast cn)
+                  unless isArray $ throwM . EncodeException $ "filter clause must take an array: " ++ show c
+                  liftIO $ FFI.addClause i cn
+            when cl $ do
+              cl <- encodeM cl
+              liftIO $ FFI.setCleanup i cl
+            return' i
+          A.Alloca { A.allocatedType = alt, A.numElements = n, A.alignment = alignment } -> do
+             alt' <- encodeM alt
+             n' <- encodeM n
+             i <- liftIO $ FFI.buildAlloca builder alt' n' s
+             unless (alignment == 0) $ liftIO $ FFI.setInstrAlignment i (fromIntegral alignment)
+             return' i
+          A.CleanupPad { A.parentPad = parentPad, A.args = args } -> do
+            parentPad' <- encodeM parentPad
+            (numArgs, args') <- encodeM args
+            i <- liftIO $ FFI.buildCleanupPad builder parentPad' args' numArgs s
+            return' i
+          A.CatchPad { A.catchSwitch = catchSwitch, A.args = args } -> do
+            catchSwitch' <- encodeM catchSwitch
+            (numArgs, args') <- encodeM args
+            i <- liftIO $ FFI.buildCatchPad builder catchSwitch' args' numArgs s
+            return' i
+          o -> $(TH.caseE [| o |] $
+                  [TH.match
+                   (TH.recP fullName [ (f,) <$> (TH.varP . TH.mkName . TH.nameBase $ f) | f <- encodeFieldNames ])
+                   (TH.normalB (TH.doE handlerBody))
+                   []
+                   |
+                   (name, ID.instructionKind -> k) <- Map.toList ID.instructionDefs,
+                   case (k, name) of
+                     (ID.Unary, _) -> True
+                     (ID.Binary, _) -> True
+                     (ID.Cast, _) -> True
+                     (ID.Memory, "Alloca") -> False
+                     (ID.Memory, _) -> True
+                     _ -> False,
+                   let
+                     TH.RecC fullName (unzip3 -> (fieldNames, _, _)) = findInstrFields name
+                     encodeFieldNames = filter (\f -> TH.nameBase f /= "metadata") fieldNames
+                     encodeMFields = map TH.nameBase encodeFieldNames
+                     handlerBody = ([
+                       TH.bindS (if s == "fastMathFlags" then TH.tupP [] else TH.varP (TH.mkName s))
+                           [| encodeM $(TH.dyn s) |] | s <- encodeMFields
+                      ] ++ [
+                       TH.bindS (TH.varP (TH.mkName "i")) [| liftIO $ $(
+                          foldl1 TH.appE . map TH.dyn $
+                           [ "FFI.build" ++ name, "builder" ] ++ (encodeMFields List.\\ [ "fastMathFlags" ]) ++ [ "s" ]
+                        ) |],
+                       TH.noBindS [| return' $(TH.dyn "i") |]
+                      ])
+                  ] ++
+                  (map (\p -> TH.match p (TH.normalB [|inconsistentCases "Instruction" o|]) [])
+                       [[p|A.Alloca{}|],
+                        [p|A.ICmp{}|],
+                        [p|A.FCmp{}|],
+                        [p|A.Phi{}|],
+                        [p|A.Select{}|],
+                        [p|A.Freeze{}|],
+                        [p|A.Call{}|],
+                        [p|A.VAArg{}|],
+                        [p|A.ExtractElement{}|],
+                        [p|A.InsertElement{}|],
+                        [p|A.ShuffleVector{}|],
+                        [p|A.ExtractValue{}|],
+                        [p|A.InsertValue{}|],
+                        [p|A.LandingPad{}|],
+                        [p|A.CatchPad{}|],
+                        [p|A.CleanupPad{}|]])
+                )
+
+        setMD inst (A.metadata o)
+        return (inst, act)
+   |]
+ )
+
+
+instance DecodeM DecodeAST a (Ptr FFI.Instruction) => DecodeM DecodeAST (DecodeAST (A.Named a)) (Ptr FFI.Instruction) where
+  decodeM i = do
+    t <- typeOf i
+    w <- if t == A.VoidType then (return A.Do) else (return (A.:=) `ap` getLocalName i)
+    return $ return w `ap` decodeM i
+
+guardNonVoidType :: (MonadIO m, MonadThrow m) => Ptr FFI.Instruction -> String -> m ()
+guardNonVoidType instr expr = do
+  ty <- (liftIO . runDecodeAST . typeOf) instr
+  case ty of
+    A.VoidType -> throwM (EncodeException ("Instruction of type void must not have a name: " ++ expr))
+    _ -> return ()
+
+instance (EncodeM EncodeAST a (Ptr FFI.Instruction), Show a) => EncodeM EncodeAST (A.Named a) (Ptr FFI.Instruction) where
+  encodeM (A.Do o) = encodeM o
+  encodeM assgn@(n A.:= o) = do
+    i <- encodeM o
+    let v = FFI.upCast i
+    n' <- encodeM n
+    liftIO $ FFI.setValueName v n'
+    defineLocal n v
+    guardNonVoidType i (show assgn)
+    return i
+
+instance (EncodeM EncodeAST a (Ptr FFI.Instruction, EncodeAST ()), Show a) => EncodeM EncodeAST (A.Named a) (EncodeAST ()) where
+  encodeM (A.Do o) = liftM snd $ (encodeM o :: EncodeAST (Ptr FFI.Instruction, EncodeAST ()))
+  encodeM assgn@(n A.:= o) = do
+    (i, later) <- encodeM o
+    let v = FFI.upCast (i :: Ptr FFI.Instruction)
+    n' <- encodeM n
+    liftIO $ FFI.setValueName v n'
+    defineLocal n v
+    guardNonVoidType i (show assgn)
+    return later
diff --git a/src/LLVM/Internal/InstructionDefs.hs b/src/LLVM/Internal/InstructionDefs.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/InstructionDefs.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  CPP
+  #-}
+module LLVM.Internal.InstructionDefs (
+  astInstructionRecs,
+  astConstantRecs,
+  instructionDefs,
+  ID.InstructionKind(..),
+  ID.InstructionDef(..),
+  instrP,
+  innerJoin,
+  outerJoin
+  ) where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+import qualified Language.Haskell.TH.Quote as TH
+
+import Data.Map (Map)
+import qualified Data.Map as Map
+
+import qualified LLVM.Internal.FFI.InstructionDefs as ID
+
+import qualified LLVM.AST.Instruction as A
+import qualified LLVM.AST.Constant as A.C
+
+$(do
+   let ctorRecs t = do
+#if __GLASGOW_HASKELL__ < 800
+         TH.TyConI (TH.DataD _ _ _ cons _) <- TH.reify t
+#else
+         TH.TyConI (TH.DataD _ _ _ _ cons _) <- TH.reify t
+#endif
+         TH.dataToExpQ (const Nothing) $ [ (TH.nameBase n, rec) | rec@(TH.RecC n _) <- cons ]
+
+   [d|
+      astInstructionRecs :: Map String TH.Con
+      astInstructionRecs = Map.fromList $(ctorRecs ''A.Instruction)
+      astConstantRecs :: Map String TH.Con
+      astConstantRecs = Map.fromList $(ctorRecs ''A.C.Constant)
+    |]
+ )
+
+instructionDefs :: Map String ID.InstructionDef
+instructionDefs = Map.fromList [ ((refName . ID.cAPIName $ i), i) | i <- ID.instructionDefs ]
+  where
+    refName "AtomicCmpXchg" = "CmpXchg"
+    refName "PHI" = "Phi"
+    refName x = x
+
+innerJoin :: Ord k => Map k a -> Map k b -> Map k (a,b)
+innerJoin = Map.intersectionWith (,)
+
+outerJoin :: Ord k => Map k a -> Map k b -> Map k (Maybe a, Maybe b)
+outerJoin xs ys = Map.unionWith combine
+                  (Map.map (\a -> (Just a, Nothing)) xs)
+                  (Map.map (\b -> (Nothing, Just b)) ys)
+    where
+      combine (Just a, Nothing) (Nothing, Just b) = (Just a, Just b)
+      combine _ _ = error "outerJoin: the impossible happened"
+
+instrP :: TH.QuasiQuoter
+instrP = TH.QuasiQuoter {
+  TH.quoteExp = undefined,
+  TH.quotePat = let m = Map.fromList [ (ID.cAPIName i, ID.cppOpcode i) | i <- ID.instructionDefs ]
+             in TH.dataToPatQ (const Nothing) . (m Map.!),
+  TH.quoteType = undefined,
+  TH.quoteDec = undefined
+ }
diff --git a/src/LLVM/Internal/IntegerPredicate.hs b/src/LLVM/Internal/IntegerPredicate.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/IntegerPredicate.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.IntegerPredicate where
+
+import LLVM.Internal.Coding
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.AST.IntegerPredicate as A.IPred
+
+genCodingInstance [t| A.IPred.IntegerPredicate |] ''FFI.ICmpPredicate [
+  (FFI.iCmpPredEQ, A.IPred.EQ),
+  (FFI.iCmpPredNE, A.IPred.NE),
+  (FFI.iCmpPredUGT, A.IPred.UGT),
+  (FFI.iCmpPredUGE, A.IPred.UGE),
+  (FFI.iCmpPredULT, A.IPred.ULT),
+  (FFI.iCmpPredULE, A.IPred.ULE),
+  (FFI.iCmpPredSGT, A.IPred.SGT),
+  (FFI.iCmpPredSGE, A.IPred.SGE),
+  (FFI.iCmpPredSLT, A.IPred.SLT),
+  (FFI.iCmpPredSLE, A.IPred.SLE)
+ ]
diff --git a/src/LLVM/Internal/LibraryFunction.hsc b/src/LLVM/Internal/LibraryFunction.hsc
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/LibraryFunction.hsc
@@ -0,0 +1,38 @@
+{-# LANGUAGE
+  MultiParamTypeClasses
+ #-}
+module LLVM.Internal.LibraryFunction where
+
+import LLVM.Prelude
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Coding
+
+#include "LLVM/Internal/FFI/LibFunc.h"
+
+#{
+define hsc_inject(m) { \
+  struct { const char *s; unsigned n; } *p, list[] = { LLVM_HS_FOR_EACH_LIB_FUNC(m) }; \
+  hsc_printf("data LibraryFunction\n"); \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf("  %s LF__%s\n", (p == list ? "=" : "|"), p->s); \
+  } \
+  hsc_printf("  deriving (Eq, Ord, Enum, Bounded, Read, Show)"); \
+  hsc_printf("\n"); \
+  hsc_printf("instance Monad m => EncodeM m LibraryFunction FFI.LibFunc where\n"); \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf("  encodeM LF__%s = return (FFI.LibFunc %u)\n", p->s, p->n); \
+  } \
+  hsc_printf("\n"); \
+  hsc_printf("instance Monad m => DecodeM m LibraryFunction FFI.LibFunc where\n"); \
+  for(p = list; p < list + sizeof(list)/sizeof(list[0]); ++p) { \
+    hsc_printf("  decodeM (FFI.LibFunc %u) = return LF__%s \n", p->n, p->s); \
+  } \
+  hsc_printf("  decodeM f = error (\"Unknown libfunc: \" <> show f)\n"); \
+}
+}
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1LibFunc.html#abf8f6830387f338fed0bce2e65108c6f>
+#define Mac(n) { #n, LLVMLibFunc__ ## n },
+#{inject Mac}
diff --git a/src/LLVM/Internal/Linking.hs b/src/LLVM/Internal/Linking.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Linking.hs
@@ -0,0 +1,31 @@
+module LLVM.Internal.Linking
+  ( loadLibraryPermanently
+  , getSymbolAddressInProcess
+  )where
+
+import LLVM.Prelude
+
+import Foreign.C.String
+import Foreign.Ptr
+import LLVM.Internal.Coding
+import LLVM.Internal.OrcJIT
+import qualified LLVM.Internal.FFI.OrcJIT as FFI
+import qualified LLVM.Internal.FFI.DynamicLibrary as DL
+import qualified LLVM.Internal.FFI.RTDyldMemoryManager as Dyld
+
+-- | Get the address of the given symbol in
+--   the current process' address space.
+getSymbolAddressInProcess
+  :: MangledSymbol -> IO WordPtr
+getSymbolAddressInProcess (MangledSymbol sym) = do
+  symStr <- FFI.mangledSymbolString sym
+  fromIntegral <$> Dyld.getSymbolAddressInProcess symStr
+
+-- | Loads the given dynamic library permanently. If 'Nothing'
+--   is given, this will make the symbols from the current
+--   process available.
+loadLibraryPermanently
+  :: Maybe FilePath
+  -> IO Bool
+loadLibraryPermanently (Just fp) = decodeM =<< withCString fp DL.loadLibraryPermanently
+loadLibraryPermanently Nothing = decodeM =<< DL.loadLibraryPermanently nullPtr
diff --git a/src/LLVM/Internal/MemoryBuffer.hs b/src/LLVM/Internal/MemoryBuffer.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/MemoryBuffer.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+module LLVM.Internal.MemoryBuffer where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Unsafe as BS
+import Foreign.Ptr
+
+import LLVM.Exception
+import LLVM.Internal.Coding
+import LLVM.Internal.String
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.MemoryBuffer as FFI
+
+data Specification 
+  = Bytes { name :: String,  content :: BS.ByteString }
+  | File { pathName :: String }
+
+instance (MonadThrow m, MonadIO m, MonadAnyCont IO m) => EncodeM m Specification (FFI.OwnerTransfered (Ptr FFI.MemoryBuffer)) where
+  encodeM spec = liftM FFI.OwnerTransfered $ do
+    case spec of
+      Bytes name content -> do
+        (s,l) <- anyContToM $ BS.unsafeUseAsCStringLen (BS.snoc content 0)
+        name <- encodeM name
+        nullTerminate <- encodeM True
+        liftIO $ FFI.createMemoryBufferWithMemoryRange s (fromIntegral (l-1)) name nullTerminate
+      File pathName -> do
+        pathName <- encodeM pathName
+        mbPtr <- alloca
+        msgPtr <- alloca
+        result <- decodeM =<< (liftIO $ FFI.createMemoryBufferWithContentsOfFile pathName mbPtr msgPtr)
+        when result $ do
+          msg <- decodeM msgPtr
+          throwM (EncodeException msg)
+        peek mbPtr          
+
+instance (MonadThrow m, MonadIO m, MonadAnyCont IO m) => EncodeM m Specification (Ptr FFI.MemoryBuffer) where
+  encodeM spec = do
+    FFI.OwnerTransfered mb <- encodeM spec
+    anyContToM $ bracket (return mb) FFI.disposeMemoryBuffer
+
+instance MonadIO d => DecodeM d BS.ByteString (Ptr FFI.MemoryBuffer) where
+  decodeM p = do
+    s <- liftIO $ FFI.getBufferStart p
+    l <- liftIO $ FFI.getBufferSize p
+    liftIO $ BS.packCStringLen (s, fromIntegral l)
+
+instance MonadIO d => DecodeM d String (Ptr FFI.MemoryBuffer) where
+  decodeM = decodeM . UTF8ByteString <=< decodeM
diff --git a/src/LLVM/Internal/Metadata.hs b/src/LLVM/Internal/Metadata.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Metadata.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.Metadata where
+
+import LLVM.Prelude
+
+import Control.Monad.State hiding (mapM, forM)
+import Control.Monad.AnyCont
+
+import Foreign.Ptr
+
+import qualified Foreign.Marshal.Array as FMA
+import qualified Data.Array as Array
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.Metadata as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+
+import LLVM.Internal.Context
+import LLVM.Internal.Coding
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.Value ()
+
+import Foreign.C
+
+instance EncodeM EncodeAST ShortByteString FFI.MDKindID where
+  encodeM s = do
+    Context c <- gets encodeStateContext
+    s <- encodeM s
+    liftIO $ FFI.getMDKindIDInContext c s
+
+getMetadataKindNames :: Context -> DecodeAST ()
+getMetadataKindNames (Context c) = scopeAnyCont $ do
+  let g n = do
+        ps <- allocaArray n
+        ls <- allocaArray n
+        n' <- liftIO $ FFI.getMDKindNames c ps ls n
+        if n' > n
+         then g n'
+         else do
+           csls <- return zip
+                   `ap` liftIO (FMA.peekArray (fromIntegral n') ps)
+                   `ap` liftIO (FMA.peekArray (fromIntegral n') ls)
+           mapM decodeM csls
+  strs <- g 16
+  modify $ \s -> s { metadataKinds = Array.listArray (0, fromIntegral (length strs) - 1) strs }
+
+instance DecodeM DecodeAST ShortByteString FFI.MDKindID where
+  decodeM (FFI.MDKindID k) = gets $ (Array.! (fromIntegral k)) . metadataKinds
+
+instance DecodeM DecodeAST ShortByteString (Ptr FFI.MDString) where
+  -- LLVM appears to use null pts to indicate empty byte string fields
+  -- including literal empty strings
+  decodeM = getByteStringFromFFI FFI.getMDStringValue
+
+getByteStringFromFFI :: (Ptr a -> Ptr CUInt -> IO CString) -> Ptr a -> DecodeAST ShortByteString
+getByteStringFromFFI _ p | nullPtr == p = return mempty
+getByteStringFromFFI f p = do
+  np <- alloca
+  s <- liftIO $ f p np
+  n <- peek np
+  decodeM (s, n)
diff --git a/src/LLVM/Internal/Module.hs b/src/LLVM/Internal/Module.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Module.hs
@@ -0,0 +1,566 @@
+{-#
+  LANGUAGE
+  TemplateHaskell,
+  ScopedTypeVariables,
+  MultiParamTypeClasses
+  #-}
+-- | This Haskell module is for/of functions for handling LLVM modules.
+module LLVM.Internal.Module where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.Trans.Except
+import Control.Monad.State (gets)
+import Control.Monad.Trans
+
+import Foreign.Ptr
+import Foreign.C
+import Data.IORef
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Short as SBS
+import qualified Data.Map as Map
+
+import qualified LLVM.Internal.FFI.Assembly as FFI
+import qualified LLVM.Internal.FFI.Attribute as FFI
+import qualified LLVM.Internal.FFI.Builder as FFI
+import qualified LLVM.Internal.FFI.Bitcode as FFI
+import qualified LLVM.Internal.FFI.Function as FFI
+import qualified LLVM.Internal.FFI.GlobalAlias as FFI
+import qualified LLVM.Internal.FFI.GlobalValue as FFI
+import qualified LLVM.Internal.FFI.GlobalVariable as FFI
+import qualified LLVM.Internal.FFI.Iterate as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.MemoryBuffer as FFI
+import qualified LLVM.Internal.FFI.Metadata as FFI
+import qualified LLVM.Internal.FFI.Module as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.RawOStream as FFI
+import qualified LLVM.Internal.FFI.Target as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+
+import LLVM.Internal.Attribute
+import LLVM.Internal.BasicBlock
+import LLVM.Internal.Coding
+import LLVM.Internal.Context
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.Function
+import LLVM.Internal.Global
+import LLVM.Internal.Instruction ()
+import qualified LLVM.Internal.MemoryBuffer as MB
+import LLVM.Internal.Metadata
+import LLVM.Internal.Operand
+import LLVM.Internal.RawOStream
+import LLVM.Internal.String
+import LLVM.Internal.Target
+import LLVM.Internal.Type
+import LLVM.Internal.Value
+
+import LLVM.DataLayout
+import LLVM.Exception
+
+import qualified LLVM.AST as A
+import qualified LLVM.AST.DataLayout as A
+import qualified LLVM.AST.AddrSpace as A
+import qualified LLVM.AST.Global as A.G
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Module.html>
+newtype Module = Module (IORef (Ptr FFI.Module))
+
+newModule :: Ptr FFI.Module -> IO (Module)
+newModule m = fmap Module (newIORef m)
+
+readModule :: MonadIO m => Module -> m (Ptr FFI.Module)
+readModule (Module ref) = liftIO $ readIORef ref
+
+-- | Signal that a module does no longer exist and thus must not be
+-- disposed. It is the responsibility of the caller to ensure that the
+-- module has been disposed. If you use only the functions provided by
+-- llvm-hs you should never call this yourself.
+deleteModule :: Module -> IO ()
+deleteModule (Module r) = writeIORef r nullPtr
+
+-- | A newtype to distinguish strings used for paths from other strings
+newtype File = File FilePath
+  deriving (Eq, Ord, Read, Show)
+
+-- | link LLVM modules - move or copy parts of a source module into a
+-- destination module.  Note that this operation is not commutative -
+-- not only concretely (e.g. the destination module is modified,
+-- becoming the result) but abstractly (e.g. unused private globals in
+-- the source module do not appear in the result, but similar globals
+-- in the destination remain). The source module is destroyed. May
+-- throw a 'LinkException'.
+linkModules ::
+     Module -- ^ The module into which to link
+  -> Module -- ^ The module to link into the other (this module is destroyed)
+  -> IO ()
+linkModules dest src  = runAnyContT' return $ do
+  dest' <- readModule dest
+  src' <- readModule src
+  result <- decodeM =<< liftIO (FFI.linkModules dest' src')
+  -- linkModules takes care of deleting the sourcemodule
+  liftIO $ deleteModule src
+  when result (throwM $ LinkException "Couldn’t link modules")
+
+class LLVMAssemblyInput s where
+  llvmAssemblyMemoryBuffer :: (MonadThrow m, MonadIO m, MonadAnyCont IO m)
+                              => s -> m (FFI.OwnerTransfered (Ptr FFI.MemoryBuffer))
+
+instance LLVMAssemblyInput (String, String) where
+  llvmAssemblyMemoryBuffer (id, s) = do
+    UTF8ByteString bs <- encodeM s
+    encodeM (MB.Bytes id bs)
+
+instance LLVMAssemblyInput (String, ByteString) where
+  llvmAssemblyMemoryBuffer (id, s) = do
+    encodeM (MB.Bytes id s)
+
+instance LLVMAssemblyInput String where
+  llvmAssemblyMemoryBuffer s = llvmAssemblyMemoryBuffer ("<string>", s)
+
+instance LLVMAssemblyInput ByteString where
+  llvmAssemblyMemoryBuffer s = llvmAssemblyMemoryBuffer ("<string>", s)
+
+instance LLVMAssemblyInput File where
+  llvmAssemblyMemoryBuffer (File p) = encodeM (MB.File p)
+
+-- | parse 'Module' from LLVM assembly. May throw 'ParseFailureException'.
+withModuleFromLLVMAssembly :: LLVMAssemblyInput s
+                              => Context -> s -> (Module -> IO a) -> IO a
+withModuleFromLLVMAssembly (Context c) s f = runAnyContT' return $ do
+  mb <- llvmAssemblyMemoryBuffer s
+  msgPtr <- alloca
+  m <- anyContToM $ bracket (newModule =<< FFI.parseLLVMAssembly c mb msgPtr) (FFI.disposeModule <=< readModule)
+  m' <- readModule m
+  when (m' == nullPtr) $ throwM . ParseFailureException =<< decodeM msgPtr
+  liftIO $ f m
+
+-- | generate LLVM assembly from a 'Module'
+moduleLLVMAssembly :: Module -> IO ByteString
+moduleLLVMAssembly m = do
+  resultRef <- newIORef Nothing
+  let saveBuffer :: Ptr CChar -> CSize -> IO ()
+      saveBuffer start size = do
+        r <- decodeM (start, size)
+        writeIORef resultRef (Just r)
+  m' <- readModule m
+  FFI.withBufferRawPWriteStream saveBuffer $ FFI.writeLLVMAssembly m' . FFI.upCast
+  Just s <- readIORef resultRef
+  return s
+
+-- | write LLVM assembly for a 'Module' to a file
+writeLLVMAssemblyToFile :: File -> Module -> IO ()
+writeLLVMAssemblyToFile (File path) m = runAnyContT' return $ do
+  m' <- readModule m
+  withFileRawOStream path False True $ FFI.writeLLVMAssembly m'
+
+class BitcodeInput b where
+  bitcodeMemoryBuffer :: (MonadThrow m, MonadIO m, MonadAnyCont IO m)
+                         => b -> m (Ptr FFI.MemoryBuffer)
+
+instance BitcodeInput (String, BS.ByteString) where
+  bitcodeMemoryBuffer (s, bs) = encodeM (MB.Bytes s bs)
+
+instance BitcodeInput File where
+  bitcodeMemoryBuffer (File p) = encodeM (MB.File p)
+
+-- | parse 'Module' from LLVM bitcode. May throw 'ParseFailureException'.
+withModuleFromBitcode :: BitcodeInput b => Context -> b -> (Module -> IO a) -> IO a
+withModuleFromBitcode (Context c) b f = runAnyContT' return $ do
+  mb <- bitcodeMemoryBuffer b
+  msgPtr <- alloca
+  m <- anyContToM $ bracket (newModule =<< FFI.parseBitcode c mb msgPtr) (FFI.disposeModule <=< readModule)
+  m' <- readModule m
+  when (m' == nullPtr) $ throwM . ParseFailureException =<< decodeM msgPtr
+  liftIO $ f m
+
+-- | generate LLVM bitcode from a 'Module'
+moduleBitcode :: Module -> IO BS.ByteString
+moduleBitcode m = do
+  m' <- readModule m
+  withBufferRawOStream (FFI.writeBitcode m')
+
+-- | write LLVM bitcode from a 'Module' into a file
+writeBitcodeToFile :: File -> Module -> IO ()
+writeBitcodeToFile (File path) m = runAnyContT' return $ do
+  m' <- readModule m
+  withFileRawOStream path False False $ FFI.writeBitcode m'
+
+-- | May throw 'TargetMachineEmitException'.
+targetMachineEmit :: FFI.CodeGenFileType -> TargetMachine -> Module -> Ptr FFI.RawPWriteStream -> IO ()
+targetMachineEmit fileType (TargetMachine tm) m os = runAnyContT' return $ do
+  msgPtr <- alloca
+  m' <- readModule m
+  r <- decodeM =<< (liftIO $ FFI.targetMachineEmit tm m' os fileType msgPtr)
+  when r $ throwM . TargetMachineEmitException =<< decodeM msgPtr
+
+-- | May throw 'FdStreamException' and 'TargetMachineEmitException'.
+emitToFile :: FFI.CodeGenFileType -> TargetMachine -> File -> Module -> IO ()
+emitToFile fileType tm (File path) m = runAnyContT' return $ do
+  withFileRawPWriteStream path False False $ targetMachineEmit fileType tm m
+
+-- | May throw 'TargetMachineEmitException'.
+emitToByteString :: FFI.CodeGenFileType -> TargetMachine -> Module -> IO BS.ByteString
+emitToByteString fileType tm m = runAnyContT' return $ do
+  withBufferRawPWriteStream $ targetMachineEmit fileType tm m
+
+-- | write target-specific assembly directly into a file
+writeTargetAssemblyToFile :: TargetMachine -> File -> Module -> IO ()
+writeTargetAssemblyToFile = emitToFile FFI.codeGenFileTypeAssembly
+
+-- | produce target-specific assembly as a 'ByteString'
+moduleTargetAssembly :: TargetMachine -> Module -> IO ByteString
+moduleTargetAssembly tm m = emitToByteString FFI.codeGenFileTypeAssembly tm m
+
+-- | produce target-specific object code as a 'ByteString'
+moduleObject :: TargetMachine -> Module -> IO BS.ByteString
+moduleObject = emitToByteString FFI.codeGenFileTypeObject
+
+-- | write target-specific object code directly into a file
+writeObjectToFile :: TargetMachine -> File -> Module -> IO ()
+writeObjectToFile = emitToFile FFI.codeGenFileTypeObject
+
+setTargetTriple :: Ptr FFI.Module -> ShortByteString -> EncodeAST ()
+setTargetTriple m t = do
+  t <- encodeM t
+  liftIO $ FFI.setTargetTriple m t
+
+getTargetTriple :: Ptr FFI.Module -> IO (Maybe ShortByteString)
+getTargetTriple m = do
+  s <- decodeM =<< liftIO (FFI.getTargetTriple m)
+  return $ if SBS.null s then Nothing else Just s
+
+setDataLayout :: Ptr FFI.Module -> A.DataLayout -> EncodeAST ()
+setDataLayout m dl = do
+  s <- encodeM (dataLayoutToString dl)
+  liftIO $ FFI.setDataLayout m s
+
+getDataLayout :: Ptr FFI.Module -> IO (Maybe A.DataLayout)
+getDataLayout m = do
+  dlString <- decodeM =<< FFI.getDataLayout m
+  either fail return . runExcept . parseDataLayout A.BigEndian $ dlString
+
+-- | Execute a function after encoding the module in LLVM’s internal representation.
+-- May throw 'EncodeException'.
+withModuleFromAST :: Context -> A.Module -> (Module -> IO a) -> IO a
+withModuleFromAST context ast =
+  bracket (createModuleFromAST context ast) disposeModule
+
+-- | Encode the module AST in LLVM’s internal representation.
+-- May throw 'EncodeException'.
+createModuleFromAST :: Context -> A.Module -> IO Module
+createModuleFromAST context@(Context c) (A.Module moduleId sourceFileName dataLayout triple definitions) = runEncodeAST context $ do
+  moduleId <- encodeM moduleId
+  m <- liftIO $ newModule =<< FFI.moduleCreateWithNameInContext moduleId c
+  ffiMod <- readModule m
+  sourceFileName' <- encodeM sourceFileName
+  liftIO $ FFI.setSourceFileName ffiMod sourceFileName'
+  Context context <- gets encodeStateContext
+  traverse_ (setDataLayout ffiMod) dataLayout
+  traverse_ (setTargetTriple ffiMod) triple
+  let sequencePhases :: EncodeAST [EncodeAST (EncodeAST (EncodeAST (EncodeAST ())))] -> EncodeAST ()
+      sequencePhases l = (l >>= (sequence >=> sequence >=> sequence >=> sequence)) >> (return ())
+  sequencePhases $ forM definitions $ \d -> case d of
+   A.TypeDefinition n t -> do
+     (t', n') <- createNamedType n
+     defineType n n' t'
+     return $ do
+       traverse_ (setNamedType t') t
+       return . return . return . return $ ()
+
+   A.COMDAT n csk -> do
+     n' <- encodeM n
+     csk <- encodeM csk
+     cd <- liftIO $ FFI.getOrInsertCOMDAT ffiMod n'
+     liftIO $ FFI.setCOMDATSelectionKind cd csk
+     defineCOMDAT n cd
+     return . return . return . return . return $ ()
+
+   A.MetadataNodeDefinition i md -> return . return $ do
+     t <- liftIO $ FFI.createTemporaryMDNodeInContext context
+     defineMDNode i t
+     return $ do
+       n <- encodeM md
+       liftIO $ FFI.metadataReplaceAllUsesWith (FFI.upCast t) (FFI.upCast n)
+       defineMDNode i n
+       return $ return ()
+
+   A.NamedMetadataDefinition n ids -> return . return . return . return $ do
+     n <- encodeM n
+     ids <- encodeM (map A.MDRef ids :: [A.MDRef A.MDNode])
+     nm <- liftIO $ FFI.getOrAddNamedMetadata ffiMod n
+     liftIO $ FFI.namedMetadataAddOperands nm ids
+     return ()
+
+   A.ModuleInlineAssembly s -> do
+     s <- encodeM s
+     liftIO $ FFI.moduleAppendInlineAsm ffiMod (FFI.ModuleAsm s)
+     return . return . return . return . return $ ()
+
+   A.FunctionAttributes gid attrs -> do
+     attrs <- encodeM attrs
+     defineAttributeGroup gid attrs
+     return . return . return . return . return $ ()
+
+   A.GlobalDefinition g -> return . phase $ do
+     eg' :: EncodeAST (Ptr FFI.GlobalValue) <- case g of
+       g@(A.GlobalVariable { A.G.name = n }) -> do
+         typ <- encodeM (A.G.type' g)
+         g' <- liftIO $ withName n $ \gName ->
+                   FFI.addGlobalInAddressSpace ffiMod typ gName
+                          (fromIntegral ((\(A.AddrSpace a) -> a) $ A.G.addrSpace g))
+         defineGlobal n g'
+         setThreadLocalMode g' (A.G.threadLocalMode g)
+         liftIO $ do
+           hua <- encodeM (A.G.unnamedAddr g)
+           FFI.setUnnamedAddr (FFI.upCast g') hua
+           ic <- encodeM (A.G.isConstant g)
+           FFI.setGlobalConstant g' ic
+         return $ do
+           traverse_ ((liftIO . FFI.setInitializer g') <=< encodeM) (A.G.initializer g)
+           setSection g' (A.G.section g)
+           setCOMDAT g' (A.G.comdat g)
+           setAlignment g' (A.G.alignment g)
+           setMetadata (FFI.upCast g') (A.G.metadata g)
+           return (FFI.upCast g')
+       (a@A.G.GlobalAlias { A.G.name = n }) -> do
+         typ <- encodeM (A.G.type' a)
+         as <- encodeM (A.G.addrSpace a)
+         a' <- liftIO $ withName n $ \name -> FFI.justAddAlias ffiMod typ as name
+         defineGlobal n a'
+         liftIO $ do
+           hua <- encodeM (A.G.unnamedAddr a)
+           FFI.setUnnamedAddr (FFI.upCast a') hua
+         return $ do
+           setThreadLocalMode a' (A.G.threadLocalMode a)
+           (liftIO . FFI.setAliasee a') =<< encodeM (A.G.aliasee a)
+           return (FFI.upCast a')
+       (A.Function _ _ _ cc rAttrs resultType fName (args, isVarArgs) attrs _ _ _ gc prefix blocks personality metadata) -> do
+         typ <- encodeM $ A.FunctionType resultType [t | A.Parameter t _ _ <- args] isVarArgs
+         f <- liftIO . withName fName $ \fName -> FFI.addFunction ffiMod fName typ
+         defineGlobal fName f
+         cc <- encodeM cc
+         liftIO $ FFI.setFunctionCallingConvention f cc
+         setFunctionAttributes f (AttributeList attrs rAttrs [pa | A.Parameter _ _ pa <- args])
+         setPrefixData f prefix
+         setSection f (A.G.section g)
+         setCOMDAT f (A.G.comdat g)
+         setAlignment f (A.G.alignment g)
+         setGC f gc
+         setPersonalityFn f personality
+         forM_ blocks $ \(A.BasicBlock bName _ _) -> do
+           b <- liftIO $ withName bName $ \bName -> FFI.appendBasicBlockInContext context f bName
+           defineBasicBlock fName bName b
+         phase $ do
+           let nParams = length args
+           ps <- allocaArray nParams
+           liftIO $ FFI.getParams f ps
+           params <- peekArray nParams ps
+           forM_ (zip args params) $ \(A.Parameter _ n _, p) -> do
+             defineLocal n p
+             n <- encodeM n
+             liftIO $ FFI.setValueName (FFI.upCast p) n
+           finishInstrs <- forM blocks $ \(A.BasicBlock bName namedInstrs term) -> do
+             b <- encodeM bName
+             (do
+               builder <- gets encodeStateBuilder
+               liftIO $ FFI.positionBuilderAtEnd builder b)
+             finishes <- mapM encodeM namedInstrs :: EncodeAST [EncodeAST ()]
+             void (encodeM term :: EncodeAST (Ptr FFI.Instruction))
+             return (sequence_ finishes)
+           sequence_ finishInstrs
+           locals <- gets $ Map.toList . encodeStateLocals
+           forM_ [ n | (n, ForwardValue _) <- locals ] $ \n -> undefinedReference "local" n
+           setMetadata (FFI.upCast f) metadata
+           return (FFI.upCast f)
+     return $ do
+       g' <- eg'
+       setLinkage g' (A.G.linkage g)
+       setVisibility g' (A.G.visibility g)
+       setDLLStorageClass g' (A.G.dllStorageClass g)
+       return $ return ()
+  return m
+
+-- | Destroys a module created by 'createModuleFromAST'.
+disposeModule :: Module -> IO ()
+disposeModule m = FFI.disposeModule =<< readModule m
+
+-- | Retrieves the context associated with a module.
+moduleContext :: Module -> IO Context
+moduleContext m = Context <$> (FFI.getModuleContext =<< readModule m)
+
+-- This returns a nested DecodeAST to allow interleaving of different
+-- decoding steps. Take a look at the call site in moduleAST for more
+-- details.
+decodeGlobalVariables :: Ptr FFI.Module -> DecodeAST (DecodeAST [A.G.Global])
+decodeGlobalVariables mod = do
+  ffiGlobals <- liftIO $ FFI.getXs (FFI.getFirstGlobal mod) FFI.getNextGlobal
+  fmap sequence . forM ffiGlobals $ \g -> do
+    A.PointerType t as <- typeOf g
+    n <- getGlobalName g
+    return $
+      A.GlobalVariable
+        <$> return n
+        <*> getLinkage g
+        <*> getVisibility g
+        <*> getDLLStorageClass g
+        <*> getThreadLocalMode g
+        <*> (liftIO $ decodeM =<< FFI.getUnnamedAddr (FFI.upCast g))
+        <*> (liftIO $ decodeM =<< FFI.isGlobalConstant g)
+        <*> return t
+        <*> return as
+        <*> (do i <- liftIO $ FFI.getInitializer g
+                if i == nullPtr
+                  then return Nothing
+                  else Just <$> decodeM i)
+        <*> getSection g
+        <*> getCOMDATName g
+        <*> getAlignment g
+        <*> getMetadata (FFI.upCast g)
+
+-- This returns a nested DecodeAST to allow interleaving of different
+-- decoding steps. Take a look at the call site in moduleAST for more
+-- details.
+decodeGlobalAliases :: Ptr FFI.Module -> DecodeAST (DecodeAST [A.G.Global])
+decodeGlobalAliases mod = do
+  ffiAliases <- liftIO $ FFI.getXs (FFI.getFirstAlias mod) FFI.getNextAlias
+  fmap sequence . forM ffiAliases $ \a -> do
+    n <- getGlobalName a
+    A.PointerType t as <- typeOf a
+    return $
+      A.G.GlobalAlias
+        <$> return n
+        <*> getLinkage a
+        <*> getVisibility a
+        <*> getDLLStorageClass a
+        <*> getThreadLocalMode a
+        <*> (liftIO $ decodeM =<< FFI.getUnnamedAddr (FFI.upCast a))
+        <*> return t
+        <*> return as
+        <*> (decodeM =<< (liftIO $ FFI.getAliasee a))
+
+getMetadata :: Ptr FFI.GlobalObject -> DecodeAST [(ShortByteString, A.MDRef A.MDNode)]
+getMetadata o = scopeAnyCont $ do
+  n <- liftIO (FFI.getNumMetadata o)
+  ks <- allocaArray n
+  ps <- allocaArray n
+  liftIO (FFI.getAllMetadata o ks ps)
+  zip <$> decodeM (n, ks) <*> decodeM (n, ps)
+
+setMetadata :: Ptr FFI.GlobalObject -> [(ShortByteString, A.MDRef A.MDNode)] -> EncodeAST ()
+setMetadata o md =
+  forM_ md $ \(kindName, node) -> do
+    kindID <- encodeM kindName
+    node <- encodeM node
+    liftIO (FFI.setMetadata o kindID node)
+
+-- This returns a nested DecodeAST to allow interleaving of different
+-- decoding steps. Take a look at the call site in moduleAST for more
+-- details.
+decodeFunctions :: Ptr FFI.Module -> DecodeAST (DecodeAST [A.G.Global])
+decodeFunctions mod = do
+  ffiFunctions <-
+    liftIO $ FFI.getXs (FFI.getFirstFunction mod) FFI.getNextFunction
+  fmap sequence . forM ffiFunctions $ \f ->
+    localScope $ do
+      A.PointerType (A.FunctionType returnType _ isVarArg) _ <- typeOf f
+      n <- getGlobalName f
+      AttributeList fAttrs rAttrs pAttrs <- getAttributeList f
+      parameters <- getParameters f pAttrs
+      decodeBlocks <- do
+        ffiBasicBlocks <-
+          liftIO $ FFI.getXs (FFI.getFirstBasicBlock f) FFI.getNextBasicBlock
+        fmap sequence . forM ffiBasicBlocks $ \b -> do
+          n <- getLocalName b
+          decodeInstructions <- getNamedInstructions b
+          decodeTerminator <- getBasicBlockTerminator b
+          return $
+            A.BasicBlock
+              <$> return n
+              <*> decodeInstructions
+              <*> decodeTerminator
+      return $
+        A.Function
+          <$> getLinkage f
+          <*> getVisibility f
+          <*> getDLLStorageClass f
+          <*> (liftIO $ decodeM =<< FFI.getFunctionCallingConvention f)
+          <*> return rAttrs
+          <*> return returnType
+          <*> return n
+          <*> return (parameters, isVarArg)
+          <*> return fAttrs
+          <*> getSection f
+          <*> getCOMDATName f
+          <*> getAlignment f
+          <*> getGC f
+          <*> getPrefixData f
+          <*> decodeBlocks
+          <*> getPersonalityFn f
+          <*> getMetadata (FFI.upCast f)
+
+decodeNamedMetadataDefinitions :: Ptr FFI.Module -> DecodeAST [A.Definition]
+decodeNamedMetadataDefinitions mod = do
+  ffiNamedMetadataNodes <-
+    liftIO $ FFI.getXs (FFI.getFirstNamedMetadata mod) FFI.getNextNamedMetadata
+  forM ffiNamedMetadataNodes $ \nm ->
+    scopeAnyCont $ do
+      n <- liftIO $ FFI.getNamedMetadataNumOperands nm
+      os <- allocaArray n
+      liftIO $ FFI.getNamedMetadataOperands nm os
+      A.NamedMetadataDefinition
+        <$> (decodeM $ FFI.getNamedMetadataName nm)
+        <*> fmap
+              (map (\(A.MDRef mid) -> mid))
+              (decodeM (n, os) :: DecodeAST [A.MDRef A.MDNode])
+
+-- | Get an LLVM.AST.'LLVM.AST.Module' from a LLVM.'Module' - i.e.
+-- raise C++ objects into an Haskell AST.
+moduleAST :: Module -> IO A.Module
+moduleAST m = runDecodeAST $ do
+  mod <- readModule m
+  c <- return Context `ap` liftIO (FFI.getModuleContext mod)
+  getMetadataKindNames c
+  A.Module
+    <$> (liftIO $ decodeM =<< FFI.getModuleIdentifier mod)
+    <*> (liftIO $ decodeM =<< FFI.getSourceFileName mod)
+    <*> (liftIO $ getDataLayout mod)
+    <*> (liftIO $ do
+           s <- decodeM =<< FFI.getTargetTriple mod
+           return $ if SBS.null s then Nothing else Just s)
+    <*> (do
+      globalDefinitions <-
+        map A.GlobalDefinition . concat <$>
+        -- Variables, aliases & functions can reference each other. To
+        -- resolve this references properly during decoding a two step
+        -- process is used: In the first step, the names of the
+        -- different definitions are stored. In the second step we can
+        -- then decode the definitions and look up the previously
+        -- stored references.
+        (join . fmap sequence . sequence)
+          [ decodeGlobalVariables mod
+          , decodeGlobalAliases mod
+          , decodeFunctions mod
+          ]
+      structDefinitions <- getStructDefinitions
+      inlineAsm <- decodeM =<< liftIO (FFI.moduleGetInlineAsm mod)
+      namedMetadata <- decodeNamedMetadataDefinitions mod
+      metadata <- getMetadataDefinitions
+      functionAttributes <- do
+        functionAttributes <- gets $ functionAttributeListIDs
+        forM functionAttributes $ \(as, gid) -> do
+          fAttrs <- A.FunctionAttributes <$> return gid <*> decodeM as
+          liftIO (FFI.disposeAttributeSet as)
+          pure fAttrs
+      comdats <- gets $ map (uncurry A.COMDAT) . Map.elems . comdats
+      return $
+        structDefinitions ++
+        inlineAsm ++
+        globalDefinitions ++
+        namedMetadata ++
+        metadata ++
+        functionAttributes ++
+        comdats)
diff --git a/src/LLVM/Internal/ObjectFile.hs b/src/LLVM/Internal/ObjectFile.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/ObjectFile.hs
@@ -0,0 +1,37 @@
+module LLVM.Internal.ObjectFile where
+
+import Control.Exception (bracket)
+import Control.Monad.IO.Class
+import Control.Monad.AnyCont
+import Foreign.Ptr
+import GHC.Stack
+
+import LLVM.Prelude
+import LLVM.Internal.Coding
+import LLVM.Internal.MemoryBuffer
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.ObjectFile as FFI
+
+newtype ObjectFile = ObjectFile (Ptr FFI.ObjectFile)
+
+-- | Dispose of an 'ObjectFile'.
+disposeObjectFile :: ObjectFile -> IO ()
+disposeObjectFile (ObjectFile obj) = FFI.disposeObjectFile obj
+
+-- | Create a object file which can later be linked with the
+-- 'LLVM.Internal.OrcJIT.LinkingLayer'.
+--
+-- Note that the file at `path` should already be a compiled object file i.e a
+-- `.o` file. This does *not* compile source files.
+createObjectFile :: HasCallStack => FilePath -> IO ObjectFile
+createObjectFile path = runAnyContT' return $ do
+  -- The ownership of the object file is transfered to the object
+  -- file, so we need to make sure that we do not free it here.
+  FFI.OwnerTransfered buf <- encodeM (File path)
+  obj <- liftIO $ FFI.createObjectFile buf
+  when (obj == nullPtr) $ error "LLVMCreateObjectFile returned a null pointer."
+  return (ObjectFile obj)
+
+-- | @bracket@-style wrapper for `createObjectFile` and `disposeObjectFile`.
+withObjectFile :: FilePath -> (ObjectFile -> IO a) -> IO a
+withObjectFile f = bracket (createObjectFile f) disposeObjectFile
diff --git a/src/LLVM/Internal/Operand.hs b/src/LLVM/Internal/Operand.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Operand.hs
@@ -0,0 +1,1304 @@
+{-# LANGUAGE
+  DuplicateRecordFields,
+  DisambiguateRecordFields,
+  MultiParamTypeClasses,
+  NamedFieldPuns,
+  OverloadedStrings,
+  PatternSynonyms,
+  QuasiQuotes,
+  RecordWildCards,
+  ScopedTypeVariables,
+  TemplateHaskell
+  #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module LLVM.Internal.Operand where
+
+import LLVM.Prelude
+
+import LLVM.Exception
+
+import Control.Monad.Catch
+import Control.Monad.State
+import Control.Monad.AnyCont
+import Data.Bits
+import Data.Functor.Identity
+import qualified Data.Map as Map
+import Data.Maybe (mapMaybe)
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.Constant as FFI
+import qualified LLVM.Internal.FFI.InlineAssembly as FFI
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.Metadata as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.Constant ()
+import LLVM.Internal.Context
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.InlineAssembly ()
+import LLVM.Internal.Metadata (getByteStringFromFFI)
+
+import qualified LLVM.AST as A hiding (GlobalVariable, Module, PointerType, type')
+import qualified LLVM.AST.Operand as A
+import qualified LLVM.AST.Constant as A (Constant(Int, integerBits, integerValue))
+
+import LLVM.Internal.FFI.LLVMCTypes (mdSubclassIdP)
+
+genCodingInstance [t|A.DebugEmissionKind|] ''FFI.DebugEmissionKind
+  [ (FFI.NoDebug, A.NoDebug)
+  , (FFI.FullDebug, A.FullDebug)
+  , (FFI.LineTablesOnly, A.LineTablesOnly)
+  ]
+
+genCodingInstance [t|A.DebugNameTableKind|] ''FFI.DebugNameTableKind
+  [ (FFI.NameTableKindDefault, A.NameTableKindDefault)
+  , (FFI.NameTableKindGNU, A.NameTableKindGNU)
+  , (FFI.NameTableKindNone, A.NameTableKindNone)
+  ]
+
+genCodingInstance [t|A.Encoding|] ''FFI.Encoding
+  [ (FFI.DwAtE_address, A.AddressEncoding)
+  , (FFI.DwAtE_boolean, A.BooleanEncoding)
+  , (FFI.DwAtE_float, A.FloatEncoding)
+  , (FFI.DwAtE_signed, A.SignedEncoding)
+  , (FFI.DwAtE_signed_char, A.SignedCharEncoding)
+  , (FFI.DwAtE_unsigned, A.UnsignedEncoding)
+  , (FFI.DwAtE_unsigned_char, A.UnsignedCharEncoding)
+  , (FFI.DwAtE_UTF, A.UTFEncoding)
+  ]
+
+genCodingInstance [t|A.ChecksumKind|] ''FFI.ChecksumKind
+  [ (FFI.ChecksumKind 1, A.MD5)
+  , (FFI.ChecksumKind 2, A.SHA1)
+  ]
+
+genCodingInstance [t|A.BasicTypeTag|] ''FFI.DwTag
+  [ (FFI.DwTag_base_type, A.BaseType)
+  , (FFI.DwTag_unspecified_type, A.UnspecifiedType)
+  ]
+
+genCodingInstance [t|A.DerivedTypeTag|] ''FFI.DwTag
+  [ (FFI.DwTag_typedef, A.Typedef)
+  , (FFI.DwTag_pointer_type, A.PointerType)
+  , (FFI.DwTag_ptr_to_member_type, A.PtrToMemberType)
+  , (FFI.DwTag_reference_type, A.ReferenceType)
+  , (FFI.DwTag_rvalue_reference_type, A.RValueReferenceType)
+  , (FFI.DwTag_const_type, A.ConstType)
+  , (FFI.DwTag_volatile_type, A.VolatileType)
+  , (FFI.DwTag_restrict_type, A.RestrictType)
+  , (FFI.DwTag_atomic_type, A.AtomicType)
+  , (FFI.DwTag_member, A.Member)
+  , (FFI.DwTag_inheritance, A.Inheritance)
+  , (FFI.DwTag_friend, A.Friend)
+  ]
+
+genCodingInstance [t|A.TemplateValueParameterTag|] ''FFI.DwTag
+  [ (FFI.DwTag_template_value_parameter, A.TemplateValueParameter)
+  , (FFI.DwTag_GNU_template_template_param, A.GNUTemplateTemplateParam)
+  , (FFI.DwTag_GNU_template_parameter_pack, A.GNUTemplateParameterPack)
+  ]
+
+genCodingInstance [t|A.Virtuality|] ''FFI.DwVirtuality
+  [ (FFI.DwVirtuality_none, A.NoVirtuality)
+  , (FFI.DwVirtuality_virtual, A.Virtual)
+  , (FFI.DwVirtuality_pure_virtual, A.PureVirtual)
+  ]
+
+genCodingInstance [t|A.DIMacroInfo|] ''FFI.Macinfo [ (FFI.DW_Macinfo_Define, A.Define), (FFI.DW_Macinfo_Undef, A.Undef) ]
+
+genCodingInstance [t|A.ImportedEntityTag|] ''FFI.DwTag
+  [ (FFI.DwTag_imported_module, A.ImportedModule)
+  , (FFI.DwTag_imported_declaration, A.ImportedDeclaration)
+  ]
+
+instance EncodeM EncodeAST ShortByteString (Ptr FFI.MDString) where
+  encodeM s = do
+    s' <- encodeM s
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getMDString c s')
+
+instance Applicative m => EncodeM m [A.DIFlag] FFI.DIFlags where
+  encodeM fs = pure (FFI.DIFlags (foldl' (.|.) 0 (map encodeFlag fs)))
+    where
+      encodeFlag f =
+        case f of
+          A.Accessibility A.Private -> 1
+          A.Accessibility A.Protected -> 2
+          A.Accessibility A.Public -> 3
+          A.FwdDecl -> 1 `shiftL` 2
+          A.AppleBlock -> 1 `shiftL` 3
+          A.ReservedBit4 -> 1 `shiftL` 4
+          A.VirtualFlag -> 1 `shiftL` 5
+          A.Artificial -> 1 `shiftL` 6
+          A.Explicit -> 1 `shiftL` 7
+          A.Prototyped -> 1 `shiftL` 8
+          A.ObjcClassComplete -> 1 `shiftL` 9
+          A.ObjectPointer -> 1 `shiftL` 10
+          A.Vector -> 1 `shiftL` 11
+          A.StaticMember -> 1 `shiftL` 12
+          A.LValueReference -> 1 `shiftL` 13
+          A.RValueReference -> 1 `shiftL` 14
+          A.InheritanceFlag A.SingleInheritance -> 1 `shiftL` 16
+          A.InheritanceFlag A.MultipleInheritance -> 2 `shiftL` 16
+          A.InheritanceFlag A.VirtualInheritance -> 3 `shiftL` 16
+          A.IntroducedVirtual -> 1 `shiftL` 18
+          A.BitField -> 1 `shiftL` 19
+          A.NoReturn -> 1 `shiftL` 20
+          A.TypePassByValue -> 1 `shiftL` 22
+          A.TypePassByReference -> 1 `shiftL` 23
+          A.EnumClass -> 1 `shiftL` 24
+          A.Thunk -> 1 `shiftL` 25
+          A.NonTrivial -> 1 `shiftL` 26
+          A.BigEndian -> 1 `shiftL` 27
+          A.LittleEndian -> 1 `shiftL` 28
+          A.AllCallsDescribed -> 1 `shiftL` 29
+
+instance Applicative m => DecodeM m [A.DIFlag] FFI.DIFlags where
+  decodeM (FFI.DIFlags f) =
+    pure $
+    accessibility ++
+    inheritance ++
+    mapMaybe flagSet flags
+    where
+      flagSet :: A.DIFlag -> Maybe A.DIFlag
+      flagSet f'
+        | f'' .&. f /= 0 = Just f'
+        | otherwise = Nothing
+        where Identity (FFI.DIFlags f'') = encodeM [f']
+      accessibility
+        | testBit f 0 && testBit f 1 = [A.Accessibility A.Public]
+        | testBit f 0 = [A.Accessibility A.Private]
+        | testBit f 1 = [A.Accessibility A.Protected]
+        | otherwise = []
+      inheritance
+        | testBit f 16 && testBit f 17 = [A.InheritanceFlag A.VirtualInheritance]
+        | testBit f 16 = [A.InheritanceFlag A.SingleInheritance]
+        | testBit f 17 = [A.InheritanceFlag A.MultipleInheritance]
+        | otherwise = []
+      flags =
+        [ A.FwdDecl
+        , A.AppleBlock
+        , A.VirtualFlag
+        , A.Artificial
+        , A.Explicit
+        , A.Prototyped
+        , A.ObjcClassComplete
+        , A.ObjectPointer
+        , A.Vector
+        , A.StaticMember
+        , A.LValueReference
+        , A.RValueReference
+        , A.IntroducedVirtual
+        , A.BitField
+        , A.NoReturn
+        , A.TypePassByValue
+        , A.TypePassByReference
+        , A.EnumClass
+        , A.Thunk
+        , A.NonTrivial
+        , A.BigEndian
+        , A.LittleEndian
+        , A.AllCallsDescribed
+        ]
+
+instance DecodeM DecodeAST A.Operand (Ptr FFI.Value) where
+  decodeM v = do
+    c <- liftIO $ FFI.isAConstant v
+    if c /= nullPtr
+     then
+      return A.ConstantOperand `ap` decodeM c
+     else
+      do m <- liftIO $ FFI.isAMetadataOperand v
+         if m /= nullPtr
+            then A.MetadataOperand <$> decodeM m
+            else A.LocalReference
+                   <$> (decodeM =<< liftIO (FFI.typeOf v))
+                   <*> getLocalName v
+
+instance DecodeM DecodeAST A.Metadata (Ptr FFI.Metadata) where
+  decodeM md = do
+    s <- liftIO $ FFI.isAMDString md
+    if s /= nullPtr
+      then A.MDString <$> decodeM s
+      else do
+        n <- liftIO $ FFI.isAMDNode md
+        if n /= nullPtr
+          then A.MDNode <$> decodeM n
+          else do
+            v <- liftIO $ FFI.isAMDValue md
+            if v /= nullPtr
+              then A.MDValue <$> decodeM v
+              else do
+                throwM (DecodeException "Metadata was not one of [MDString, MDValue, MDNode]")
+
+instance DecodeM DecodeAST (Either String A.DINode) (Ptr FFI.DINode) where
+  decodeM diN = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast diN)
+    case sId of
+      [mdSubclassIdP|DIEnumerator|] ->
+        liftM Right $ A.DIEnumerator <$> decodeM (castPtr diN :: Ptr FFI.DIEnumerator)
+      [mdSubclassIdP|DIImportedEntity|]   -> liftM Right $ A.DIImportedEntity <$> decodeM (castPtr diN :: Ptr FFI.DIImportedEntity)
+      [mdSubclassIdP|DIObjCProperty|]     -> liftM Right $ A.DIObjCProperty <$> decodeM (castPtr diN :: Ptr FFI.DIObjCProperty)
+      [mdSubclassIdP|DISubrange|]         -> liftM Right $ A.DISubrange <$> decodeM (castPtr diN :: Ptr FFI.DISubrange)
+      [mdSubclassIdP|DIBasicType|]        -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DICompositeType|]    -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DIDerivedType|]      -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DISubroutineType|]   -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DILexicalBlock|]     -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DILexicalBlockFile|] -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DIFile|]             -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DINamespace|]        -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DISubprogram|]       -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DICompileUnit|]      -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+      [mdSubclassIdP|DIModule|]           -> liftM Right $ A.DIScope <$> decodeM (castPtr diN :: Ptr FFI.DIScope)
+
+      [mdSubclassIdP|DIGlobalVariable|]   -> liftM Right $ A.DIVariable <$> decodeM (castPtr diN :: Ptr FFI.DIVariable)
+      [mdSubclassIdP|DILocalVariable|]    -> liftM Right $ A.DIVariable <$> decodeM (castPtr diN :: Ptr FFI.DIVariable)
+
+      [mdSubclassIdP|DITemplateTypeParameter|]  -> liftM Right $ A.DITemplateParameter <$> decodeM (castPtr diN :: Ptr FFI.DITemplateParameter)
+      [mdSubclassIdP|DITemplateValueParameter|] -> liftM Right $ A.DITemplateParameter <$> decodeM (castPtr diN :: Ptr FFI.DITemplateParameter)
+
+      [mdSubclassIdP|MDString|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (MDString)")
+      [mdSubclassIdP|ConstantAsMetadata|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (ConstantAsMetadata)")
+      [mdSubclassIdP|LocalAsMetadata|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (LocalAsMetadata)")
+      [mdSubclassIdP|DistinctMDOperandPlaceholder|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DistinctMDOperandPlaceholder)")
+      [mdSubclassIdP|MDTuple|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (MDTuple)")
+      [mdSubclassIdP|DILocation|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DILocation)")
+      [mdSubclassIdP|DIExpression|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DIExpression)")
+      [mdSubclassIdP|DIGlobalVariableExpression|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DIGlobalVariableExpression)")
+      [mdSubclassIdP|GenericDINode|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (GenericDINode)")
+      [mdSubclassIdP|DIMacro|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DIMacro)")
+      [mdSubclassIdP|DIMacroFile|] -> liftM Left $ pure ("Lifting to Haskell not implemented for toplevel DINode kind: " <> show sId <> " (DIMacroFile)")
+
+      _ -> throwM (DecodeException ("Unknown subclass id for DINode: " <> show sId))
+
+instance EncodeM EncodeAST A.DICount (Ptr FFI.Metadata) where
+  encodeM count = do
+    case count of
+      A.DICountConstant i -> do
+        let constant = A.MDValue (A.ConstantOperand (A.Int { A.integerBits = 64, A.integerValue = toInteger i }))
+        encodeM constant
+      A.DICountVariable v -> do
+        encodeM (A.MDNode $ A.DINode . A.DIVariable <$> v)
+
+instance EncodeM EncodeAST A.DIBound (Ptr FFI.Metadata) where
+  encodeM bound = do
+    case bound of
+      A.DIBoundConstant i -> do
+        let constant = A.MDValue (A.ConstantOperand (A.Int { A.integerBits = 64, A.integerValue = toInteger i }))
+        encodeM constant
+      A.DIBoundVariable v -> do
+        encodeM (A.MDNode (A.DINode . A.DIVariable <$> v))
+      A.DIBoundExpression e -> do
+        encodeM (A.MDNode (A.DIExpression <$> e))
+
+instance DecodeM DecodeAST A.DICount (Ptr FFI.Metadata) where
+  decodeM m = do
+    c <- liftIO $ FFI.isAMDValue m
+    if c /= nullPtr
+    then do
+      (A.ConstantOperand A.Int { A.integerValue = i }) <- decodeM c
+      pure (A.DICountConstant (fromInteger i))
+    else do
+      v <- decodeM =<< liftIO (FFI.isADIVariable m)
+      pure (A.DICountVariable v)
+
+instance DecodeM DecodeAST A.DIBound (Ptr FFI.Metadata) where
+  decodeM m = do
+    c <- liftIO $ FFI.isAMDValue m
+    if c /= nullPtr
+    then do
+      (A.ConstantOperand A.Int { A.integerValue = i }) <- decodeM c
+      pure (A.DIBoundConstant (fromInteger i))
+    else do
+      v <- liftIO (FFI.isADIVariable m)
+      if v /= nullPtr
+        then do
+          v' <- decodeM =<< pure v
+          pure (A.DIBoundVariable v')
+        else do
+          e <- decodeM =<< liftIO (FFI.isADIExpression m)
+          pure (A.DIBoundExpression e)
+
+instance EncodeM EncodeAST A.DISubrange (Ptr FFI.DISubrange) where
+  encodeM (A.Subrange {..}) = do
+    Context c <- gets encodeStateContext
+    count' <- encodeM count
+    lowerBound' <- encodeM lowerBound
+    upperBound' <- encodeM upperBound
+    stride' <- encodeM stride
+    liftIO (FFI.getDISubrangeVariableFields c count' lowerBound' upperBound' stride')
+
+instance DecodeM DecodeAST A.DISubrange (Ptr FFI.DISubrange) where
+  decodeM r = do
+    count <- decodeM =<< liftIO (FFI.getDISubrangeCount r)
+    lowerBound <- decodeM =<< liftIO (FFI.getDISubrangeLowerBound r)
+    upperBound <- decodeM =<< liftIO (FFI.getDISubrangeUpperBound r)
+    stride <- decodeM =<< liftIO (FFI.getDISubrangeStride r)
+    pure (A.Subrange count lowerBound upperBound stride)
+
+instance EncodeM EncodeAST A.DIEnumerator (Ptr FFI.DIEnumerator) where
+  encodeM (A.Enumerator {..}) = do
+    name <- encodeM name
+    isUnsigned <- encodeM isUnsigned
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIEnumerator c value isUnsigned name)
+
+instance DecodeM DecodeAST A.DIEnumerator (Ptr FFI.DIEnumerator) where
+  decodeM e = do
+    value <- liftIO (FFI.getDIEnumeratorValue e)
+    isUnsigned <- decodeM =<< liftIO (FFI.getDIEnumeratorIsUnsigned e)
+    name <- decodeM =<< liftIO (FFI.getDIEnumeratorName e)
+    pure (A.Enumerator value isUnsigned name)
+
+instance EncodeM EncodeAST A.DINode (Ptr FFI.DINode) where
+  encodeM (A.DISubrange r) = do
+    ptr <- encodeM r
+    pure (FFI.upCast (ptr :: Ptr FFI.DISubrange))
+  encodeM (A.DIEnumerator e) = do
+    ptr <- encodeM e
+    pure (FFI.upCast (ptr :: Ptr FFI.DIEnumerator))
+  encodeM (A.DIScope s) = do
+    ptr <- encodeM s
+    pure (FFI.upCast (ptr :: Ptr FFI.DIScope))
+  encodeM (A.DIVariable v) = do
+    ptr <- encodeM v
+    pure (FFI.upCast (ptr :: Ptr FFI.DIVariable))
+  encodeM (A.DITemplateParameter p) = do
+    ptr <- encodeM p
+    pure (FFI.upCast (ptr :: Ptr FFI.DITemplateParameter))
+  encodeM (A.DIImportedEntity e) = do
+    ptr <- encodeM e
+    pure (FFI.upCast (ptr :: Ptr FFI.DIImportedEntity))
+  encodeM (A.DIObjCProperty o) = FFI.upCast <$> (encodeM o :: EncodeAST (Ptr FFI.DIObjCProperty))
+
+instance DecodeM DecodeAST A.DIScope (Ptr FFI.DIScope) where
+  decodeM p = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast p)
+    case sId of
+      [mdSubclassIdP|DINamespace|] -> A.DINamespace <$> decodeM (castPtr p :: Ptr FFI.DINamespace)
+      [mdSubclassIdP|DIFile|] -> A.DIFile <$> decodeM (castPtr p :: Ptr FFI.DIFile)
+      [mdSubclassIdP|DILexicalBlock|]     -> A.DILocalScope <$> decodeM (castPtr p :: Ptr FFI.DILocalScope)
+      [mdSubclassIdP|DILexicalBlockFile|] -> A.DILocalScope <$> decodeM (castPtr p :: Ptr FFI.DILocalScope)
+      [mdSubclassIdP|DISubprogram|]       -> A.DILocalScope <$> decodeM (castPtr p :: Ptr FFI.DILocalScope)
+
+      [mdSubclassIdP|DIBasicType|]      -> A.DIType <$> decodeM (castPtr p :: Ptr FFI.DIType)
+      [mdSubclassIdP|DICompositeType|]  -> A.DIType <$> decodeM (castPtr p :: Ptr FFI.DIType)
+      [mdSubclassIdP|DIDerivedType|]    -> A.DIType <$> decodeM (castPtr p :: Ptr FFI.DIType)
+      [mdSubclassIdP|DISubroutineType|] -> A.DIType <$> decodeM (castPtr p :: Ptr FFI.DIType)
+
+      [mdSubclassIdP|DICompileUnit|] -> A.DICompileUnit <$> decodeM (castPtr p :: Ptr FFI.DICompileUnit)
+      [mdSubclassIdP|DIModule|]      -> A.DIModule <$> decodeM (castPtr p :: Ptr FFI.DIModule)
+
+      _ -> throwM (DecodeException ("Unknown subclass id for DIScope: " <> show sId))
+
+instance DecodeM DecodeAST A.DINamespace (Ptr FFI.DINamespace) where
+  decodeM p = do
+    scope <- decodeM =<< liftIO (FFI.getScopeScope (FFI.upCast p))
+    name  <- getByteStringFromFFI FFI.getScopeName (FFI.upCast p)
+    exported <- decodeM =<< liftIO (FFI.getNamespaceExportedSymbols (castPtr p))
+    return (A.Namespace name scope exported)
+
+instance EncodeM EncodeAST A.DINamespace (Ptr FFI.DINamespace) where
+  encodeM A.Namespace {..} = do
+    name <- encodeM name
+    scope <- encodeM scope
+    exportSyms <- encodeM exportSymbols
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDINamespace c scope name exportSyms)
+
+instance DecodeM DecodeAST A.DIModule (Ptr FFI.DIModule) where
+  decodeM p = do
+    scope <- decodeM =<< liftIO (FFI.getScopeScope (FFI.upCast p))
+    name <- getByteStringFromFFI FFI.getScopeName (FFI.upCast p)
+    let m = castPtr p :: Ptr FFI.DIModule
+    configurationMacros <- decodeM =<< liftIO (FFI.getDIModuleConfigurationMacros m)
+    includePath <- decodeM =<< liftIO (FFI.getDIModuleIncludePath m)
+    apiNotesFile <- decodeM =<< liftIO (FFI.getDIModuleAPINotesFile m)
+    lineNo <- liftIO (FFI.getDIModuleLineNo m)
+    pure A.Module
+      { A.scope = scope
+      , A.name = name
+      , A.configurationMacros = configurationMacros
+      , A.includePath = includePath
+      , A.apiNotesFile = apiNotesFile
+      , A.lineNo = lineNo
+      }
+
+instance EncodeM EncodeAST A.DIModule (Ptr FFI.DIModule) where
+  encodeM A.Module {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    configurationMacros <- encodeM configurationMacros
+    includePath <- encodeM includePath
+    apiNotesFile <- encodeM apiNotesFile
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIModule c scope name configurationMacros includePath apiNotesFile lineNo)
+
+instance DecodeM DecodeAST A.DICompileUnit (Ptr FFI.DICompileUnit) where
+  decodeM p = do
+    language <- decodeM =<< liftIO (FFI.getDICompileUnitLanguage p)
+    file <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast p))
+    producer <- decodeM =<< liftIO (FFI.getDICompileUnitProducer p)
+    optimized <- decodeM =<< liftIO (FFI.getDICompileUnitOptimized p)
+    flags <- decodeM =<< liftIO (FFI.getDICompileUnitFlags p)
+    runtimeVersion <- decodeM =<< liftIO (FFI.getDICompileUnitRuntimeVersion p)
+    splitDebugFilename <- decodeM =<< liftIO (FFI.getDICompileUnitSplitDebugFilename p)
+    emissionKind <- decodeM =<< liftIO (FFI.getDICompileUnitEmissionKind p)
+    dwoid <- decodeM =<< liftIO (FFI.getDICompileUnitDWOId p)
+    splitDebugInlining <- decodeM =<< liftIO (FFI.getDICompileUnitSplitDebugInlining p)
+    debugInfoForProfiling <- decodeM =<< liftIO (FFI.getDICompileUnitDebugInfoForProfiling p)
+    enums <- decodeM =<< liftIO (FFI.getDICompileUnitEnumTypes p)
+    retainedTypes' <- decodeM =<< liftIO (FFI.getDICompileUnitRetainedTypes p)
+    let toRetainedType :: A.MDRef A.DIScope -> DecodeAST (A.MDRef (Either A.DIType A.DISubprogram))
+        toRetainedType (A.MDRef i) = pure (A.MDRef i)
+        toRetainedType (A.MDInline (A.DIType ty)) = pure (A.MDInline (Left ty))
+        toRetainedType (A.MDInline (A.DILocalScope (A.DISubprogram p))) = pure (A.MDInline (Right p))
+        toRetainedType (A.MDInline e) = throwM (DecodeException ("Retained type must be DISubprogram or DIType but got " <> show e))
+    retainedTypes <- traverse toRetainedType retainedTypes'
+    globals <- decodeM =<< liftIO (FFI.getDICompileUnitGlobalVariables p)
+    entities <- decodeM =<< liftIO (FFI.getDICompileUnitImportedEntities p)
+    macros <- decodeM =<< liftIO (FFI.getDICompileUnitMacros p)
+    nameTableKind <- decodeM =<< liftIO (FFI.getDICompileUnitNameTableKind p)
+    rangesBaseAddress <- decodeM =<< liftIO (FFI.getDICompileUnitRangesBaseAddress p)
+    pure A.CompileUnit
+      { A.language = language
+      , A.file = file
+      , A.producer = producer
+      , A.optimized = optimized
+      , A.flags = flags
+      , A.runtimeVersion = runtimeVersion
+      , A.splitDebugFileName = splitDebugFilename
+      , A.emissionKind = emissionKind
+      , A.enums = enums
+      , A.retainedTypes = retainedTypes
+      , A.globals = globals
+      , A.imports = entities
+      , A.macros = macros
+      , A.dWOId = dwoid
+      , A.splitDebugInlining = splitDebugInlining
+      , A.debugInfoForProfiling = debugInfoForProfiling
+      , A.nameTableKind = nameTableKind
+      , A.rangesBaseAddress = rangesBaseAddress
+      }
+
+instance EncodeM EncodeAST A.DICompileUnit (Ptr FFI.DICompileUnit) where
+  encodeM (A.CompileUnit {..}) = do
+    language <- encodeM language
+    file <- encodeM file
+    producer <- encodeM producer
+    optimized <- encodeM optimized
+    flags <- encodeM flags
+    runtimeVersion <- encodeM runtimeVersion
+    debugFileName <- encodeM splitDebugFileName
+    emissionKind <- encodeM emissionKind
+    enums <- encodeM enums
+    retainedTypes <- encodeM (map (fmap (either A.DIType (A.DILocalScope . A.DISubprogram))) retainedTypes)
+    globals <- encodeM globals
+    imports <- encodeM imports
+    macros <- encodeM macros
+    dwoid <- encodeM dWOId
+    splitDebugInlining <- encodeM splitDebugInlining
+    debugInfoForProfiling <- encodeM debugInfoForProfiling
+    nameTableKind <- encodeM nameTableKind
+    rangesBaseAddress <- encodeM rangesBaseAddress
+    Context c <- gets encodeStateContext
+    liftIO $ FFI.getDICompileUnit
+      c
+      language file producer optimized flags
+      runtimeVersion debugFileName emissionKind enums retainedTypes
+      globals imports macros dwoid splitDebugInlining
+      debugInfoForProfiling nameTableKind rangesBaseAddress
+
+instance EncodeM EncodeAST A.DIScope (Ptr FFI.DIScope) where
+  encodeM (A.DIFile f) = FFI.upCast <$> (encodeM f :: EncodeAST (Ptr FFI.DIFile))
+  encodeM (A.DICompileUnit cu) = FFI.upCast <$> (encodeM cu :: EncodeAST (Ptr FFI.DICompileUnit))
+  encodeM (A.DIType t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DIType))
+  encodeM (A.DILocalScope t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DILocalScope))
+  encodeM (A.DINamespace ns) = FFI.upCast <$> (encodeM ns :: EncodeAST (Ptr FFI.DINamespace))
+  encodeM (A.DIModule m) = FFI.upCast <$> (encodeM m :: EncodeAST (Ptr FFI.DIModule))
+
+instance DecodeM DecodeAST A.DIFile (Ptr FFI.DIFile) where
+  decodeM diF = do
+    fname <- decodeM =<< liftIO (FFI.getFileFilename diF)
+    dir   <- decodeM =<< liftIO (FFI.getFileDirectory diF)
+    mayChecksum <- decodeM =<< liftIO (FFI.getFileChecksumValue diF)
+    case mayChecksum of
+      Nothing -> pure (A.File fname dir Nothing)
+      Just checksum -> do
+        csk <- decodeM =<< liftIO (FFI.getFileChecksumKind diF)
+        pure (A.File fname dir (Just (A.ChecksumInfo csk checksum)))
+
+instance EncodeM EncodeAST A.DIFile (Ptr FFI.DIFile) where
+  encodeM (A.File {..}) = do
+    filename <- encodeM filename
+    directory <- encodeM directory
+    Context c <- gets encodeStateContext
+    case checksum of
+      Nothing -> liftIO (FFI.getDIFile c filename directory (FFI.ChecksumKind 0) nullPtr)
+      Just (A.ChecksumInfo {..}) -> do
+        checksumValue <- encodeM checksumValue
+        checksumKind <- encodeM checksumKind
+        liftIO (FFI.getDIFile c filename directory checksumKind checksumValue)
+
+instance EncodeM EncodeAST (Maybe A.Encoding) FFI.Encoding where
+  encodeM Nothing = pure (FFI.Encoding 0)
+  encodeM (Just e) = encodeM e
+
+instance DecodeM DecodeAST (Maybe A.Encoding) FFI.Encoding where
+  decodeM (FFI.Encoding 0) = pure Nothing
+  decodeM e = Just <$> decodeM e
+
+instance EncodeM EncodeAST A.DIType (Ptr FFI.DIType) where
+  encodeM (A.DIBasicType t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DIBasicType))
+  encodeM (A.DIDerivedType t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DIDerivedType))
+  encodeM (A.DISubroutineType t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DISubroutineType))
+  encodeM (A.DICompositeType t) = FFI.upCast <$> (encodeM t :: EncodeAST (Ptr FFI.DICompositeType))
+
+instance DecodeM DecodeAST A.DICompositeType (Ptr FFI.DICompositeType) where
+  decodeM diTy = do
+    tag <- liftIO (FFI.getTag (FFI.upCast diTy))
+    size <- liftIO (FFI.getTypeSizeInBits (FFI.upCast diTy))
+    align <- liftIO (FFI.getTypeAlignInBits (FFI.upCast diTy))
+    elements <- liftIO (FFI.getElements diTy)
+    scope <- decodeM =<< liftIO (FFI.getScopeScope (FFI.upCast diTy))
+    name <- decodeM =<< liftIO (FFI.getTypeName (FFI.upCast diTy))
+    file <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast diTy))
+    line <- liftIO (FFI.getTypeLine (FFI.upCast diTy))
+    flags <- decodeM =<< liftIO (FFI.getTypeFlags (FFI.upCast diTy))
+    runtimeLang <- liftIO (FFI.getRuntimeLang diTy)
+    vtableHolder <- decodeM =<< liftIO (FFI.getVTableHolder diTy)
+    type' <- decodeM =<< liftIO (FFI.getCompositeBaseType diTy)
+    identifier <- decodeM =<< liftIO (FFI.getIdentifier diTy)
+    case tag of
+      FFI.DwTag_array_type -> do
+        subscripts <- decodeM (FFI.TupleArray elements :: FFI.TupleArray FFI.DISubrange)
+        pure (A.DIArrayType subscripts type' size align flags)
+      FFI.DwTag_enumeration_type -> do
+        values <- decodeM (FFI.TupleArray elements :: FFI.TupleArray FFI.DIEnumerator)
+        pure (A.DIEnumerationType scope name file line values type' identifier size align)
+      FFI.DwTag_structure_type -> do
+        elements <- decodeM (FFI.TupleArray elements :: FFI.TupleArray FFI.DIScope)
+        elements <- traverse fromCompElement elements
+        pure (A.DIStructureType scope name file line flags type' elements runtimeLang vtableHolder identifier size align)
+      FFI.DwTag_class_type -> do
+        elements <- decodeM (FFI.TupleArray elements :: FFI.TupleArray FFI.DIScope)
+        elements <- traverse fromCompElement elements
+        vtableHolder <- decodeM =<< liftIO (FFI.getVTableHolder diTy)
+        params <- decodeM =<< liftIO (FFI.getTemplateParams diTy)
+        pure (A.DIClassType scope name file line flags type' elements vtableHolder params identifier size align)
+      FFI.DwTag_union_type -> do
+        elements <- decodeM (FFI.TupleArray elements :: FFI.TupleArray FFI.DIScope)
+        elements <- traverse fromCompElement elements
+        pure (A.DIUnionType scope name file line flags elements runtimeLang identifier size align)
+      _ -> throwM (DecodeException ("Unknown tag of DICompositeType: " <> show tag))
+
+fromCompElement :: A.MDRef A.DIScope -> DecodeAST (A.MDRef (Either A.DIDerivedType A.DISubprogram))
+fromCompElement (A.MDRef r) = pure (A.MDRef r)
+fromCompElement (A.MDInline (A.DIType (A.DIDerivedType ty))) = pure (A.MDInline (Left ty))
+fromCompElement (A.MDInline (A.DILocalScope (A.DISubprogram p))) = pure (A.MDInline (Right p))
+fromCompElement (A.MDInline e) = throwM (DecodeException ("Elements of DIClassType, DIStructureType and DIUnionType must be DIDerivedType or DISubprogram but got " <> show e))
+
+toCompElement :: A.MDRef (Either A.DIDerivedType A.DISubprogram) -> A.MDRef A.DIScope
+toCompElement = fmap (either (A.DIType . A.DIDerivedType) (A.DILocalScope . A.DISubprogram))
+
+instance EncodeM EncodeAST A.DICompositeType (Ptr FFI.DICompositeType) where
+  encodeM A.DIArrayType {..} = do
+    subscripts <- encodeM subscripts
+    elementTy <- encodeM elementTy
+    flags <- encodeM flags
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIArrayType c subscripts elementTy sizeInBits alignInBits flags)
+  encodeM A.DIEnumerationType {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    file <- encodeM file
+    elements <- encodeM values
+    underlyingType <- encodeM baseType
+    identifier <- encodeM identifier
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIEnumerationType c scope name file line sizeInBits alignInBits elements underlyingType identifier)
+  encodeM A.DIStructureType {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    file <- encodeM file
+    flags <- encodeM flags
+    derivedFrom <- encodeM derivedFrom
+    elements <- encodeM (map toCompElement elements)
+    vtableHolder <- encodeM vtableHolder
+    identifier <- encodeM identifier
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIStructType c scope name file line sizeInBits alignInBits flags derivedFrom elements runtimeLang vtableHolder identifier)
+  encodeM A.DIUnionType {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    file <- encodeM file
+    flags <- encodeM flags
+    elements <- encodeM (map toCompElement elements)
+    identifier <- encodeM identifier
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIUnionType c scope name file line sizeInBits alignInBits flags elements runtimeLang identifier)
+  encodeM A.DIClassType {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    file <- encodeM file
+    flags <- encodeM flags
+    derivedFrom <- encodeM derivedFrom
+    elements <- encodeM (map toCompElement elements)
+    vtableHolder <- encodeM vtableHolder
+    params <- encodeM templateParams
+    identifier <- encodeM identifier
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIClassType c scope name file line sizeInBits alignInBits flags derivedFrom elements vtableHolder params identifier)
+
+instance DecodeM DecodeAST A.DIType (Ptr FFI.DIType) where
+  decodeM diTy = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast diTy)
+    case sId of
+      [mdSubclassIdP|DIBasicType|] ->
+        A.DIBasicType <$> decodeM (castPtr diTy :: Ptr FFI.DIBasicType)
+      [mdSubclassIdP|DICompositeType|] ->
+        A.DICompositeType <$> decodeM (castPtr diTy :: Ptr FFI.DICompositeType)
+      [mdSubclassIdP|DIDerivedType|]    -> A.DIDerivedType <$> decodeM (castPtr diTy :: Ptr FFI.DIDerivedType)
+      [mdSubclassIdP|DISubroutineType|] -> A.DISubroutineType <$> decodeM (castPtr diTy :: Ptr FFI.DISubroutineType)
+      _ -> throwM (DecodeException ("Unknown subclass id for DIType: " <> show sId))
+
+instance DecodeM DecodeAST A.DIBasicType (Ptr FFI.DIBasicType) where
+  decodeM diTy = do
+    tag <- decodeM =<< liftIO (FFI.getTag (FFI.upCast diTy))
+    size <- liftIO (FFI.getTypeSizeInBits (FFI.upCast diTy))
+    align <- liftIO (FFI.getTypeAlignInBits (FFI.upCast diTy))
+    name <- decodeM =<< liftIO (FFI.getTypeName (FFI.upCast diTy))
+    encoding <- decodeM =<< liftIO (FFI.getBasicTypeEncoding diTy)
+    flags <- decodeM =<< liftIO (FFI.getTypeFlags (castPtr diTy :: Ptr FFI.DIType))
+    pure (A.BasicType name size align encoding tag flags)
+
+instance EncodeM EncodeAST A.DIBasicType (Ptr FFI.DIBasicType) where
+  encodeM A.BasicType {..} = do
+    tag <- encodeM tag
+    name <- encodeM name
+    encoding <- encodeM encoding
+    flags <- encodeM flags
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIBasicType c tag name sizeInBits alignInBits encoding flags)
+
+
+instance EncodeM EncodeAST A.DISubroutineType (Ptr FFI.DISubroutineType) where
+  encodeM A.SubroutineType {..} = do
+    flags <- encodeM flags
+    types <- encodeM typeArray
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDISubroutineType c flags cc types)
+
+instance DecodeM DecodeAST A.DISubroutineType (Ptr FFI.DISubroutineType) where
+  decodeM p = do
+    flags <- decodeM =<< liftIO (FFI.getTypeFlags (FFI.upCast p))
+    cc <-  liftIO (FFI.getSubroutineCC p)
+    arr <- decodeM =<< liftIO (FFI.getSubroutineTypeArray p)
+    pure A.SubroutineType
+      { A.flags = flags
+      , A.cc = cc
+      , A.typeArray = arr
+      }
+
+instance EncodeM EncodeAST A.DIDerivedType (Ptr FFI.DIDerivedType) where
+  encodeM A.DerivedType {..} = do
+    tag <- encodeM tag
+    name <- encodeM name
+    file <- encodeM file
+    line <- encodeM line
+    scope <- encodeM scope
+    type' <- encodeM baseType
+    (addrSpace, addrSpacePresent) <- encodeM addressSpace
+    flags <- encodeM flags
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDIDerivedType c tag name file line scope type' sizeInBits alignInBits offsetInBits addrSpace addrSpacePresent flags)
+
+instance DecodeM DecodeAST A.DIDerivedType (Ptr FFI.DIDerivedType) where
+  decodeM diTy = do
+    let diTy' = FFI.upCast diTy
+    name <- decodeM =<< liftIO (FFI.getTypeName diTy')
+    file   <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast diTy))
+    scope  <- decodeM =<< liftIO (FFI.getScopeScope (FFI.upCast diTy))
+    ty <- decodeM =<< liftIO (FFI.getDerivedBaseType diTy')
+    line     <- liftIO (FFI.getTypeLine diTy')
+    size     <- liftIO (FFI.getTypeSizeInBits diTy')
+    align    <- liftIO (FFI.getTypeAlignInBits diTy')
+    offset   <- liftIO (FFI.getTypeOffsetInBits diTy')
+    tag      <- decodeM =<< liftIO (FFI.getTag (FFI.upCast diTy))
+    flags <- decodeM =<< liftIO (FFI.getTypeFlags diTy')
+    addressSpace <- decodeOptional (FFI.getDerivedAddressSpace diTy')
+    pure A.DerivedType
+      { A.tag = tag
+      , A.name = name
+      , A.file = file
+      , A.line = line
+      , A.scope = scope
+      , A.baseType = ty
+      , A.sizeInBits = size
+      , A.alignInBits = align
+      , A.offsetInBits = offset
+      , A.addressSpace = addressSpace
+      , A.flags = flags
+      }
+
+instance EncodeM EncodeAST A.DIVariable (Ptr FFI.DIVariable) where
+  encodeM (A.DIGlobalVariable v) = do
+    ptr <- encodeM v
+    pure (FFI.upCast (ptr :: Ptr FFI.DIGlobalVariable))
+  encodeM (A.DILocalVariable v) = do
+    ptr <- encodeM v
+    pure (FFI.upCast (ptr :: Ptr FFI.DILocalVariable))
+
+instance DecodeM DecodeAST A.DIVariable (Ptr FFI.DIVariable) where
+  decodeM p = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast p)
+    case sId of
+      [mdSubclassIdP|DIGlobalVariable|] ->
+        A.DIGlobalVariable <$> decodeM (castPtr p :: Ptr FFI.DIGlobalVariable)
+      [mdSubclassIdP|DILocalVariable|] ->
+        A.DILocalVariable <$> decodeM (castPtr p :: Ptr FFI.DILocalVariable)
+      _ -> throwM (DecodeException ("Unknown subclass id for DIVariable: " <> show sId))
+
+instance DecodeM DecodeAST A.DIGlobalVariable (Ptr FFI.DIGlobalVariable) where
+  decodeM p = do
+    name <- decodeM =<< liftIO (FFI.getDIVariableName (FFI.upCast p))
+    scope <- decodeM =<< liftIO (FFI.getDIVariableScope (FFI.upCast p))
+    file <- decodeM =<< liftIO (FFI.getDIVariableFile (FFI.upCast p))
+    line <- decodeM =<< liftIO (FFI.getDIVariableLine (FFI.upCast p))
+    type' <- decodeM =<< liftIO (FFI.getDIVariableType (FFI.upCast p))
+    align <- liftIO (FFI.getDIVariableAlignInBits (FFI.upCast p))
+    linkageName <- decodeM =<< liftIO (FFI.getDIGlobalVariableLinkageName p)
+    local <- decodeM =<< liftIO (FFI.getDIGlobalVariableLocal p)
+    definition <- decodeM =<< liftIO (FFI.getDIGlobalVariableDefinition p)
+    decl <- decodeM =<< liftIO (FFI.getDIGlobalVariableStaticDataMemberDeclaration p)
+    pure A.GlobalVariable
+      { A.name = name
+      , A.scope = scope
+      , A.file = file
+      , A.line = line
+      , A.type' = type'
+      , A.linkageName = linkageName
+      , A.local = local
+      , A.definition = definition
+      , A.staticDataMemberDeclaration = decl
+      , A.templateParams = []
+      , A.alignInBits = align
+      }
+
+instance EncodeM EncodeAST A.DIGlobalVariable (Ptr FFI.DIGlobalVariable) where
+  encodeM A.GlobalVariable {..} = do
+    name <- encodeM name
+    scope <- encodeM scope
+    file <- encodeM file
+    line <- encodeM line
+    type' <- encodeM type'
+    linkageName <- encodeM linkageName
+    local <- encodeM local
+    definition <- encodeM definition
+    dataMemberDeclaration <- encodeM staticDataMemberDeclaration
+    templateParams <- encodeM templateParams
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIGlobalVariable c scope name linkageName file line type' local definition dataMemberDeclaration templateParams alignInBits)
+
+instance DecodeM DecodeAST A.DILocalVariable (Ptr FFI.DILocalVariable) where
+  decodeM p = do
+    name <- decodeM =<< liftIO (FFI.getDIVariableName (FFI.upCast p))
+    scope <- decodeM =<< liftIO (FFI.getDIVariableScope (FFI.upCast p))
+    file <- decodeM =<< liftIO (FFI.getDIVariableFile (FFI.upCast p))
+    line <- decodeM =<< liftIO (FFI.getDIVariableLine (FFI.upCast p))
+    type' <- decodeM =<< liftIO (FFI.getDIVariableType (FFI.upCast p))
+    align <- liftIO (FFI.getDIVariableAlignInBits (FFI.upCast p))
+    arg <- liftIO (FFI.getDILocalVariableArg p)
+    flags <- decodeM =<< liftIO (FFI.getDILocalVariableFlags p)
+    pure A.LocalVariable
+      { A.file = file
+      , A.scope = scope
+      , A.name = name
+      , A.line = line
+      , A.arg = arg
+      , A.flags = flags
+      , A.type' = type'
+      , A.alignInBits = align
+      }
+
+instance EncodeM EncodeAST A.DILocalVariable (Ptr FFI.DILocalVariable) where
+  encodeM A.LocalVariable {..} = do
+    name <- encodeM name
+    scope <- encodeM scope
+    file <- encodeM file
+    type' <- encodeM type'
+    flags <- encodeM flags
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDILocalVariable c scope name file line type' arg flags alignInBits)
+
+getDITemplateParameterName :: A.DITemplateParameter -> ShortByteString
+getDITemplateParameterName A.DITemplateTypeParameter {..} = name
+getDITemplateParameterName A.DITemplateValueParameter{..} = name
+
+getDITemplateParameterType :: A.DITemplateParameter -> Maybe (A.MDRef A.DIType)
+getDITemplateParameterType A.DITemplateTypeParameter {..} = type'
+getDITemplateParameterType A.DITemplateValueParameter{..} = type'
+
+instance EncodeM EncodeAST A.DITemplateParameter (Ptr FFI.DITemplateParameter) where
+  encodeM p = do
+    name' <- encodeM (getDITemplateParameterName p) :: EncodeAST (Ptr FFI.MDString)
+    ty <- encodeM (getDITemplateParameterType p)
+    Context c <- gets encodeStateContext
+    case p of
+      A.DITemplateTypeParameter {} ->
+        FFI.upCast <$> liftIO (FFI.getDITemplateTypeParameter c name' ty)
+      A.DITemplateValueParameter {..} -> do
+        tag <- encodeM tag
+        value <- encodeM value
+        FFI.upCast <$> liftIO (FFI.getDITemplateValueParameter c name' ty tag True value)
+
+instance DecodeM DecodeAST A.DITemplateParameter (Ptr FFI.DITemplateParameter) where
+  decodeM p = do
+    sId <- liftIO (FFI.getMetadataClassId (FFI.upCast p))
+    name <- decodeM =<< liftIO (FFI.getDITemplateParameterName p)
+    ty <- decodeM =<< liftIO (FFI.getDITemplateParameterType p)
+    case sId of
+      [mdSubclassIdP|DITemplateTypeParameter|] ->
+        pure (A.DITemplateTypeParameter name ty)
+      [mdSubclassIdP|DITemplateValueParameter|] -> do
+        value <- decodeM =<< liftIO (FFI.getDITemplateValueParameterValue (castPtr p))
+        tag <- decodeM =<< liftIO (FFI.getTag (FFI.upCast p))
+        pure (A.DITemplateValueParameter name ty value tag)
+      _ -> throwM (DecodeException ("Unknown subclass id for DITemplateParameter: " <> show sId))
+
+instance DecodeM DecodeAST A.DISubprogram (Ptr FFI.DISubprogram) where
+  decodeM p = do
+    name  <- getByteStringFromFFI FFI.getScopeName (FFI.upCast p)
+    linkageName <- decodeM =<< liftIO (FFI.getDISubprogramLinkageName p)
+    file  <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast p))
+    scope <- decodeM =<< liftIO (FFI.getScopeScope (FFI.upCast p))
+    line <- decodeM =<< liftIO (FFI.getDISubprogramLine p)
+    virtuality <- decodeM =<< liftIO (FFI.getDISubprogramVirtuality p)
+    virtualIndex <- decodeM =<< liftIO (FFI.getDISubprogramVirtualIndex p)
+    scopeLine <- decodeM =<< liftIO (FFI.getDISubprogramScopeLine p)
+    optimized <- decodeM =<< liftIO (FFI.getDISubprogramIsOptimized p)
+    definition <- decodeM =<< liftIO (FFI.getDISubprogramIsDefinition p)
+    localToUnit <- decodeM =<< liftIO (FFI.getDISubprogramLocalToUnit p)
+    thisAdjustment <- liftIO (FFI.getDISubprogramThisAdjustment p)
+    flags <- decodeM =<< liftIO (FFI.getDISubprogramFlags p)
+    type' <- decodeM =<< liftIO (FFI.getDISubprogramType p)
+    containingType <- decodeM =<< liftIO (FFI.getDISubprogramContainingType p)
+    unit <- decodeM =<< liftIO (FFI.getDISubprogramUnit p)
+    templateParams <- decodeM =<< liftIO (FFI.getDISubprogramTemplateParams p)
+    retainedNodes <- decodeM =<< liftIO (FFI.getDISubprogramRetainedNodes p)
+    thrownTypes <- decodeM =<< liftIO (FFI.getDISubprogramThrownTypes p)
+    decl <- decodeM =<< liftIO (FFI.getDISubprogramDeclaration p)
+    pure A.Subprogram
+      { A.name = name
+      , A.linkageName = linkageName
+      , A.scope = scope
+      , A.file = file
+      , A.line = line
+      , A.type' = type'
+      , A.definition = definition
+      , A.scopeLine = scopeLine
+      , A.containingType = containingType
+      , A.virtuality = virtuality
+      , A.virtualityIndex = virtualIndex
+      , A.flags = flags
+      , A.optimized = optimized
+      , A.unit = unit
+      , A.templateParams = templateParams
+      , A.declaration = decl
+      , A.retainedNodes = retainedNodes
+      , A.thrownTypes = thrownTypes
+      , A.localToUnit = localToUnit
+      , A.thisAdjustment = thisAdjustment
+      }
+
+instance EncodeM EncodeAST A.DISubprogram (Ptr FFI.DISubprogram) where
+  encodeM A.Subprogram {..} = do
+    scope <- encodeM scope
+    name <- encodeM name
+    linkageName <- encodeM linkageName
+    file <- encodeM file
+    line <- encodeM line
+    type' <- encodeM type'
+    localToUnit <- encodeM localToUnit
+    definition <- encodeM definition
+    scopeLine <- encodeM scopeLine
+    containingType <- encodeM containingType
+    virtuality <- encodeM virtuality
+    virtualityIndex <- encodeM virtualityIndex
+    flags <- encodeM flags
+    optimized <- encodeM optimized
+    unit <- encodeM unit
+    templateParams <- encodeM templateParams
+    declaration <- encodeM declaration
+    retainedNodes <- encodeM retainedNodes
+    thrownTypes <- encodeM thrownTypes
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO
+      (FFI.getDISubprogram
+        c scope name
+        linkageName file line
+        type' localToUnit definition scopeLine
+        containingType virtuality virtualityIndex
+        thisAdjustment flags optimized
+        unit templateParams declaration
+        retainedNodes thrownTypes)
+
+instance DecodeM DecodeAST A.DILocalScope (Ptr FFI.DILocalScope) where
+  decodeM ls = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast ls)
+    case sId of
+      [mdSubclassIdP|DISubprogram|] -> A.DISubprogram <$> decodeM (castPtr ls :: Ptr FFI.DISubprogram)
+      [mdSubclassIdP|DILexicalBlock|] -> A.DILexicalBlockBase <$> decodeM (castPtr ls :: Ptr FFI.DILexicalBlockBase)
+      [mdSubclassIdP|DILexicalBlockFile|] -> A.DILexicalBlockBase <$> decodeM (castPtr ls :: Ptr FFI.DILexicalBlockBase)
+      _ -> throwM (DecodeException ("Unknown subclass id for DILocalScope: " <> show sId))
+
+instance EncodeM EncodeAST A.DILocalScope (Ptr FFI.DILocalScope) where
+  encodeM (A.DISubprogram sp) = do
+    ptr <- encodeM sp
+    pure (FFI.upCast (ptr :: Ptr FFI.DISubprogram))
+  encodeM (A.DILexicalBlockBase b) = do
+    ptr <- encodeM b
+    pure (FFI.upCast (ptr :: Ptr FFI.DILexicalBlockBase))
+
+instance DecodeM DecodeAST A.DILexicalBlockBase (Ptr FFI.DILexicalBlockBase) where
+  decodeM p = do
+    sId <- liftIO (FFI.getMetadataClassId (FFI.upCast p))
+    case sId of
+      [mdSubclassIdP|DILexicalBlock|] -> do
+        scope <- decodeM =<< liftIO (FFI.getLexicalBlockScope p)
+        file  <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast p))
+        line  <- liftIO (FFI.getLexicalBlockLine p)
+        col   <- liftIO (FFI.getLexicalBlockColumn p)
+        pure (A.DILexicalBlock scope file line col)
+      [mdSubclassIdP|DILexicalBlockFile|] -> do
+        scope <- decodeM =<< liftIO (FFI.getLexicalBlockScope p)
+        file  <- decodeM =<< liftIO (FFI.getScopeFile (FFI.upCast p))
+        disc  <- liftIO (FFI.getLexicalBlockFileDiscriminator p)
+        pure (A.DILexicalBlockFile scope file disc)
+      _ -> throwM (DecodeException ("Unknown subclass id for DILexicalBlockBase: " <> show sId))
+
+instance EncodeM EncodeAST A.DILexicalBlockBase (Ptr FFI.DILexicalBlockBase) where
+  encodeM A.DILexicalBlock {..} = do
+    scope <- encodeM scope
+    file <- encodeM file
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDILexicalBlock c scope file line column)
+  encodeM A.DILexicalBlockFile {..} = do
+    scope <- encodeM scope
+    file <- encodeM file
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDILexicalBlockFile c scope file discriminator)
+
+instance DecodeM DecodeAST A.CallableOperand (Ptr FFI.Value) where
+  decodeM v = do
+    ia <- liftIO $ FFI.isAInlineAsm v
+    if ia /= nullPtr
+     then Left <$> decodeM ia
+     else Right <$> decodeM v
+
+instance EncodeM EncodeAST A.Operand (Ptr FFI.Value) where
+  encodeM (A.ConstantOperand c) = do
+    c' <- (encodeM :: A.Constant -> EncodeAST (Ptr FFI.Constant)) c
+    let v = (FFI.upCast :: Ptr FFI.Constant -> Ptr FFI.Value) c'
+    return v
+  encodeM (A.LocalReference t n) = do
+    lv <- refer encodeStateLocals n $ do
+      lv <- do
+        n <- encodeM n
+        t <- encodeM t
+        v <- liftIO $ FFI.createArgument t n
+        return $ ForwardValue v
+      modify $ \s -> s { encodeStateLocals = Map.insert n lv $ encodeStateLocals s }
+      return lv
+    return $ case lv of DefinedValue v -> v; ForwardValue v -> v
+  encodeM (A.MetadataOperand md) = do
+    md' <- encodeM md
+    Context c <- gets encodeStateContext
+    liftIO $ FFI.upCast <$> FFI.metadataOperand c md'
+
+instance EncodeM EncodeAST A.Metadata (Ptr FFI.Metadata) where
+  encodeM (A.MDString s) = do
+    Context c <- gets encodeStateContext
+    s <- encodeM s
+    FFI.upCast <$> liftIO (FFI.getMDString c s)
+  encodeM (A.MDNode mdn) = (FFI.upCast :: Ptr FFI.MDNode -> Ptr FFI.Metadata) <$> encodeM mdn
+  encodeM (A.MDValue v) = do
+     v <- encodeM v
+     mdVal <- liftIO $ FFI.mdValue v
+     return $ FFI.upCast mdVal
+
+instance EncodeM EncodeAST A.CallableOperand (Ptr FFI.Value) where
+  encodeM (Right o) = encodeM o
+  encodeM (Left i) = (FFI.upCast :: Ptr FFI.InlineAsm -> Ptr FFI.Value) <$> encodeM i
+
+instance EncodeM EncodeAST A.MDNode (Ptr FFI.MDNode) where
+  encodeM (A.MDTuple ops) = scopeAnyCont $ do
+    Context c <- gets encodeStateContext
+    ops <- encodeM ops
+    FFI.upCast <$> liftIO (FFI.getMDTuple c ops)
+  encodeM (A.DINode n) = do
+    ptr <- encodeM n
+    pure (FFI.upCast (ptr :: Ptr FFI.DINode))
+  encodeM (A.DILocation l) = FFI.upCast <$> (encodeM l :: EncodeAST (Ptr FFI.DILocation))
+  encodeM (A.DIExpression e) = FFI.upCast <$> (encodeM e :: EncodeAST (Ptr FFI.DIExpression))
+  encodeM (A.DIGlobalVariableExpression e) =
+    FFI.upCast <$> (encodeM e :: EncodeAST (Ptr FFI.DIGlobalVariableExpression))
+  encodeM (A.DIMacroNode n) = FFI.upCast <$> (encodeM n :: EncodeAST (Ptr FFI.DIMacroNode))
+
+instance EncodeM EncodeAST A.DILocation (Ptr FFI.DILocation) where
+  encodeM A.Location {..} = do
+    Context c <- gets encodeStateContext
+    scopePtr <- encodeM scope
+    liftIO (FFI.getDILocation c line column scopePtr)
+
+instance DecodeM DecodeAST A.DILocation (Ptr FFI.DILocation) where
+  decodeM p = do
+    line <- liftIO (FFI.getDILocationLine p)
+    col  <- liftIO (FFI.getDILocationColumn p)
+    scope <-  decodeM =<< liftIO (FFI.getDILocationScope p)
+    pure (A.Location line col scope)
+
+instance (MonadIO m, MonadState EncodeState m, MonadAnyCont IO m, EncodeM m a (Ptr a'), FFI.DescendentOf FFI.Metadata a') => EncodeM m [a] (FFI.TupleArray a') where
+  encodeM [] = pure (FFI.TupleArray nullPtr)
+  encodeM els = do
+    (numEls, elsPtr) <- encodeM els
+    Context c <- gets encodeStateContext
+    FFI.TupleArray <$> liftIO (FFI.getMDTuple c (numEls, castPtr (elsPtr :: Ptr (Ptr a'))))
+
+instance (MonadIO m, MonadAnyCont IO m, DecodeM m a (Ptr a')) => DecodeM m [a] (FFI.TupleArray a') where
+  decodeM (FFI.TupleArray p)
+    | p == nullPtr = pure []
+    | otherwise = do
+      decodeArray FFI.getMDNodeNumOperands getOperand (FFI.upCast p)
+    where
+      getOperand md i = (castPtr <$> FFI.getMDNodeOperand md i) :: IO (Ptr a')
+
+encodeDWOp :: A.DWOp -> [Word64]
+encodeDWOp op =
+  case op of
+    A.DW_OP_And -> [FFI.DwOp_and]
+    A.DW_OP_Bregx -> [FFI.DwOp_bregx]
+    A.DW_OP_ConstU arg -> [FFI.DwOp_constu, arg]
+    A.DW_OP_Deref -> [FFI.DwOp_deref]
+    A.DW_OP_Div -> [FFI.DwOp_div]
+    A.DW_OP_Dup -> [FFI.DwOp_dup]
+    A.DwOpFragment (A.DW_OP_LLVM_Fragment offset size) -> [FFI.DwOp_LLVM_fragment, offset, size]
+    A.DW_OP_Lit0 -> [FFI.DwOp_lit0]
+    A.DW_OP_Minus -> [FFI.DwOp_minus]
+    A.DW_OP_Mod -> [FFI.DwOp_mod]
+    A.DW_OP_Mul -> [FFI.DwOp_mul]
+    A.DW_OP_Not -> [FFI.DwOp_not]
+    A.DW_OP_Or -> [FFI.DwOp_or]
+    A.DW_OP_Plus -> [FFI.DwOp_plus]
+    A.DW_OP_PlusUConst arg -> [FFI.DwOp_plus_uconst, arg]
+    A.DW_OP_PushObjectAddress -> [FFI.DwOp_push_object_address]
+    A.DW_OP_Shl -> [FFI.DwOp_shl]
+    A.DW_OP_Shra -> [FFI.DwOp_shra]
+    A.DW_OP_Shr -> [FFI.DwOp_shr]
+    A.DW_OP_StackValue -> [FFI.DwOp_stack_value]
+    A.DW_OP_Swap -> [FFI.DwOp_swap]
+    A.DW_OP_XDeref -> [FFI.DwOp_xderef]
+    A.DW_OP_Xor -> [FFI.DwOp_xor]
+
+instance DecodeM DecodeAST [Maybe A.Metadata] (Ptr FFI.MDNode) where
+  decodeM p = decodeArray FFI.getMDNodeNumOperands FFI.getMDNodeOperand p
+
+instance DecodeM DecodeAST A.Operand (Ptr FFI.MDValue) where
+  decodeM = decodeM <=< liftIO . FFI.getMDValue
+
+instance DecodeM DecodeAST A.Metadata (Ptr FFI.MetadataAsVal) where
+  decodeM = decodeM <=< liftIO . FFI.getMetadataOperand
+
+decodeMDNode :: Ptr FFI.MDNode -> DecodeAST (Either String A.MDNode)
+decodeMDNode p = scopeAnyCont $ do
+  sId <- liftIO $ FFI.getMetadataClassId p
+  case sId of
+      [mdSubclassIdP|MDTuple|] -> liftM Right $ A.MDTuple <$> decodeM p
+      [mdSubclassIdP|DIExpression|] ->
+        liftM Right $ A.DIExpression <$> decodeM (castPtr p :: Ptr FFI.DIExpression)
+      [mdSubclassIdP|DIGlobalVariableExpression|] ->
+        liftM Right $ A.DIGlobalVariableExpression <$> decodeM (castPtr p :: Ptr FFI.DIGlobalVariableExpression)
+      [mdSubclassIdP|DILocation|] -> liftM Right $ A.DILocation <$> decodeM (castPtr p :: Ptr FFI.DILocation)
+      [mdSubclassIdP|DIMacro|] -> liftM Right $ A.DIMacroNode <$> decodeM (castPtr p :: Ptr FFI.DIMacroNode)
+      [mdSubclassIdP|DIMacroFile|] -> liftM Right $ A.DIMacroNode <$> decodeM (castPtr p :: Ptr FFI.DIMacroNode)
+      _ -> do
+        decoded <- decodeM (castPtr p :: Ptr FFI.DINode)
+        case decoded of
+          (Right din) -> liftM Right $ pure $ A.DINode din
+          (Left err) -> pure $ Left err
+
+instance DecodeM DecodeAST A.DIMacroNode (Ptr FFI.DIMacroNode) where
+  decodeM p = do
+    sId <- liftIO $ FFI.getMetadataClassId (FFI.upCast p)
+    case sId of
+      [mdSubclassIdP|DIMacro|] -> do
+        let p' = castPtr p :: Ptr FFI.DIMacro
+        macInfo <- decodeM =<< liftIO (FFI.getDIMacroMacinfo p')
+        line <- liftIO (FFI.getDIMacroLine p')
+        name <- decodeM =<< liftIO (FFI.getDIMacroName p')
+        value <- decodeM =<< liftIO (FFI.getDIMacroValue p')
+        pure (A.DIMacro macInfo line name value)
+      [mdSubclassIdP|DIMacroFile|] -> do
+        let p' = castPtr p :: Ptr FFI.DIMacroFile
+        line <- liftIO (FFI.getDIMacroFileLine p')
+        file <- decodeM =<< liftIO (FFI.getDIMacroFileFile p')
+        elements <- decodeArray FFI.getDIMacroFileNumElements FFI.getDIMacroFileElement p'
+        pure (A.DIMacroFile line file elements)
+      _ -> throwM (DecodeException ("Unknown subclass id for DIMacroNode: " <> show sId))
+
+instance EncodeM EncodeAST A.DIMacroNode (Ptr FFI.DIMacroNode) where
+  encodeM A.DIMacro {..} = do
+    macInfo <- encodeM info
+    name <- encodeM name
+    value <- encodeM value
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDIMacro c macInfo line name value)
+  encodeM A.DIMacroFile {..} = do
+    file <- encodeM file
+    elements <- encodeM elements
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDIMacroFile c line file elements)
+
+instance EncodeM EncodeAST A.DIExpression (Ptr FFI.DIExpression) where
+  encodeM A.Expression {..} = do
+    ops <- encodeM (concatMap encodeDWOp operands)
+    Context c <- gets encodeStateContext
+    FFI.upCast <$> liftIO (FFI.getDIExpression c ops)
+
+instance DecodeM DecodeAST A.DIExpression (Ptr FFI.DIExpression) where
+  decodeM diExpr = do
+    numElems <- liftIO (FFI.getDIExpressionNumElements diExpr)
+    let go i
+          | i >= numElems = pure []
+          | otherwise = do
+              op <- FFI.getDIExpressionElement diExpr i
+              case op of
+                FFI.DwOp_LLVM_fragment -> do
+                  expectElems "LLVM_fragment" i 2
+                  offset <- FFI.getDIExpressionElement diExpr (i + 1)
+                  size <- FFI.getDIExpressionElement diExpr (i + 2)
+                  (A.DwOpFragment (A.DW_OP_LLVM_Fragment offset size) :) <$> go (i + 3)
+                FFI.DwOp_stack_value -> (A.DW_OP_StackValue :) <$> go (i + 1)
+                FFI.DwOp_swap -> (A.DW_OP_Swap :) <$> go (i + 1)
+                FFI.DwOp_constu -> do
+                  expectElems "constu" i 1
+                  arg <- FFI.getDIExpressionElement diExpr (i + 1)
+                  (A.DW_OP_ConstU arg:) <$> go (i + 2)
+                FFI.DwOp_lit0 -> (A.DW_OP_Lit0 :) <$> go (i + 1)
+                FFI.DwOp_plus_uconst -> do
+                  expectElems "uconst" i 1
+                  arg <- FFI.getDIExpressionElement diExpr (i + 1)
+                  (A.DW_OP_PlusUConst arg:) <$> go (i + 2)
+                FFI.DwOp_plus -> (A.DW_OP_Plus :) <$> go (i + 1)
+                FFI.DwOp_minus -> (A.DW_OP_Minus :) <$> go (i + 1)
+                FFI.DwOp_mul -> (A.DW_OP_Mul :) <$> go (i + 1)
+                FFI.DwOp_div -> (A.DW_OP_Div :) <$> go (i + 1)
+                FFI.DwOp_mod -> (A.DW_OP_Mod :) <$> go (i + 1)
+                FFI.DwOp_not -> (A.DW_OP_Not :) <$> go (i + 1)
+                FFI.DwOp_or -> (A.DW_OP_Or :) <$> go (i + 1)
+                FFI.DwOp_xor -> (A.DW_OP_Xor :) <$> go (i + 1)
+                FFI.DwOp_and -> (A.DW_OP_And :) <$> go (i + 1)
+                FFI.DwOp_shr -> (A.DW_OP_Shr :) <$> go (i + 1)
+                FFI.DwOp_shra -> (A.DW_OP_Shra :) <$> go (i + 1)
+                FFI.DwOp_shl -> (A.DW_OP_Shl :) <$> go (i + 1)
+                FFI.DwOp_dup -> (A.DW_OP_Dup :) <$> go (i + 1)
+                FFI.DwOp_deref -> (A.DW_OP_Deref :) <$> go (i + 1)
+                FFI.DwOp_xderef -> (A.DW_OP_XDeref :) <$> go (i + 1)
+                FFI.DwOp_bregx -> (A.DW_OP_Bregx :) <$> go (i + 1)
+                FFI.DwOp_push_object_address -> (A.DW_OP_PushObjectAddress :) <$> go (i + 1)
+                _ -> throwM (DecodeException ("Unknown DW_OP " <> show op))
+        expectElems name i n =
+          when (i + n >= numElems)
+               (throwM (DecodeException ("Expected " <> show n <> " elements following DW_OP_" <>
+                                         name <> " but got " <> show (numElems - i - 1))))
+    liftIO (A.Expression <$> go 0)
+
+instance EncodeM EncodeAST A.DIGlobalVariableExpression (Ptr FFI.DIGlobalVariableExpression) where
+  encodeM A.GlobalVariableExpression {..} = do
+    var <- encodeM var
+    expr <- encodeM expr
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIGlobalVariableExpression c var expr)
+
+instance DecodeM DecodeAST A.DIGlobalVariableExpression (Ptr FFI.DIGlobalVariableExpression) where
+  decodeM p = do
+    var <- decodeM =<< liftIO (FFI.getDIGlobalVariableExpressionVariable p)
+    expr <- decodeM =<< liftIO (FFI.getDIGlobalVariableExpressionExpression p)
+    pure (A.GlobalVariableExpression var expr)
+
+instance EncodeM EncodeAST A.DIImportedEntity (Ptr FFI.DIImportedEntity) where
+  encodeM A.ImportedEntity {..} = do
+    tag <- encodeM tag
+    scope <- encodeM scope
+    entity <- encodeM entity
+    file <- encodeM file
+    name <- encodeM name
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIImportedEntity c tag scope entity file line name)
+
+instance DecodeM DecodeAST A.DIImportedEntity (Ptr FFI.DIImportedEntity) where
+  decodeM e = do
+    tag <- decodeM =<< liftIO (FFI.getTag (FFI.upCast e))
+    scope <- decodeM =<< liftIO (FFI.getDIImportedEntityScope e)
+    entity :: Either String A.DINode <- decodeM =<< liftIO (FFI.getDIImportedEntityEntity e)
+    file <- decodeM =<< liftIO (FFI.getDIImportedEntityFile e)
+    name <- decodeM =<< liftIO (FFI.getDIImportedEntityName e)
+    line <- liftIO (FFI.getDIImportedEntityLine e)
+    case entity of
+      (Right din) -> pure (A.ImportedEntity tag name scope (Just $ A.MDInline din) file line)
+      (Left _) -> pure (A.ImportedEntity tag name scope Nothing file line)
+
+instance EncodeM EncodeAST A.DIObjCProperty (Ptr FFI.DIObjCProperty) where
+  encodeM A.ObjCProperty {..} = do
+    name <- encodeM name
+    file <- encodeM file
+    getterName <- encodeM getterName
+    setterName <- encodeM setterName
+    type' <- encodeM type'
+    Context c <- gets encodeStateContext
+    liftIO (FFI.getDIObjCProperty c name file line getterName setterName attributes type')
+
+instance DecodeM DecodeAST A.DIObjCProperty (Ptr FFI.DIObjCProperty) where
+  decodeM p = do
+    name <- decodeM =<< liftIO (FFI.getDIObjCPropertyName p)
+    file <- decodeM =<< liftIO (FFI.getDIObjCPropertyFile p)
+    line <- liftIO (FFI.getDIObjCPropertyLine p)
+    getterName <- decodeM =<< liftIO (FFI.getDIObjCPropertyGetterName p)
+    setterName <- decodeM =<< liftIO (FFI.getDIObjCPropertySetterName p)
+    attributes <- liftIO (FFI.getDIObjCPropertyAttributes p)
+    type' <- decodeM =<< liftIO (FFI.getDIObjCPropertyType p)
+    pure (A.ObjCProperty name file line getterName setterName attributes type')
+
+instance {-# OVERLAPS #-} DecodeM DecodeAST (A.MDRef A.MDNode) (Ptr FFI.MDNode) where
+  decodeM p = scopeAnyCont $ do
+    sId <- liftIO $ FFI.getMetadataClassId p
+    case sId of
+      [mdSubclassIdP|DIExpression|] -> A.MDInline . A.DIExpression <$> decodeM (castPtr p :: Ptr FFI.DIExpression)
+      _ -> A.MDRef <$> getMetadataNodeID p
+
+instance (DecodeM DecodeAST a (Ptr b), FFI.DescendentOf FFI.MDNode b) => DecodeM DecodeAST (A.MDRef a) (Ptr b) where
+  decodeM p = scopeAnyCont $
+    A.MDRef <$> getMetadataNodeID (FFI.upCast p)
+
+instance (EncodeM EncodeAST a (Ptr b), FFI.DescendentOf FFI.MDNode b) => EncodeM EncodeAST (A.MDRef a) (Ptr b) where
+  encodeM (A.MDRef id) = castPtr <$> referMDNode id
+  encodeM (A.MDInline m) = encodeM m
+
+getMetadataDefinitions :: DecodeAST [A.Definition]
+getMetadataDefinitions = fix $ \continue -> do
+  mdntd <- takeMetadataNodeToDefine
+  case mdntd of
+    Nothing -> pure []
+    Just (mid, p) -> do
+      decoded <- decodeMDNode p
+      case decoded of
+        (Right mdn) ->
+          (:)
+            <$> (pure $ A.MetadataNodeDefinition mid mdn)
+            <*> continue
+        (Left _) -> continue
diff --git a/src/LLVM/Internal/OrcJIT.hs b/src/LLVM/Internal/OrcJIT.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/OrcJIT.hs
@@ -0,0 +1,319 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module LLVM.Internal.OrcJIT where
+
+import LLVM.Prelude
+
+import Control.Exception
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+import Data.Bits
+import Data.IORef
+import Foreign.C.Types
+import Foreign.C.String
+import Foreign.Ptr
+
+import LLVM.Internal.Coding
+import LLVM.Internal.Module (Module, readModule)
+import LLVM.Internal.Target (TargetMachine(..))
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.ShortByteString as SBS
+import qualified LLVM.Internal.FFI.DataLayout as FFI
+import qualified LLVM.Internal.FFI.OrcJIT as FFI
+import qualified LLVM.Internal.FFI.Target as FFI
+
+--------------------------------------------------------------------------------
+-- ExecutionSession
+--------------------------------------------------------------------------------
+
+data ExecutionSession = ExecutionSession {
+    sessionPtr :: !(Ptr FFI.ExecutionSession),
+    sessionCleanups :: !(IORef [IO ()])
+  }
+
+-- | Create a new `ExecutionSession`.
+createExecutionSession :: IO ExecutionSession
+createExecutionSession = ExecutionSession <$> FFI.createExecutionSession <*> newIORef []
+
+-- | Dispose of an `ExecutionSession`. This should be called when the
+-- `ExecutionSession` is not needed anymore.
+disposeExecutionSession :: ExecutionSession -> IO ()
+disposeExecutionSession (ExecutionSession es cleanups) = do
+  FFI.endSession es
+  sequence_ =<< readIORef cleanups
+  FFI.disposeExecutionSession es
+
+-- | `bracket`-style wrapper around `createExecutionSession` and
+-- `disposeExecutionSession`.
+withExecutionSession :: (ExecutionSession -> IO a) -> IO a
+withExecutionSession = bracket createExecutionSession disposeExecutionSession
+
+--------------------------------------------------------------------------------
+-- JITSymbol
+--------------------------------------------------------------------------------
+
+-- | Contrary to the C++ interface, we do not store the HasError flag
+-- here. Instead decoding a JITSymbol produces a sumtype based on
+-- whether that flag is set or not.
+data JITSymbolFlags =
+  JITSymbolFlags {
+    jitSymbolWeak :: !Bool -- ^ Is this a weak symbol?
+  , jitSymbolCommon :: !Bool -- ^ Is this a common symbol?
+  , jitSymbolAbsolute :: !Bool
+    -- ^ Is this an absolute symbol? This will cause LLVM to use
+    -- absolute relocations for the symbol even in position
+    -- independent code.
+  , jitSymbolExported :: !Bool -- ^ Is this symbol exported?
+  , jitSymbolCallable :: !Bool
+  , jitSymbolMaterializationSideEffectsOnly :: !Bool
+  }
+  deriving (Show, Eq, Ord)
+
+defaultJITSymbolFlags :: JITSymbolFlags
+defaultJITSymbolFlags = JITSymbolFlags False False False False False False
+
+data JITSymbol =
+  JITSymbol {
+    jitSymbolAddress :: !WordPtr, -- ^ The address of the symbol. If
+                                  -- you’ve looked up a function, you
+                                  -- need to cast this to a 'FunPtr'.
+    jitSymbolFlags :: !JITSymbolFlags -- ^ The flags of this symbol.
+  }
+  deriving (Show, Eq, Ord)
+
+data JITSymbolError = JITSymbolError ShortByteString
+  deriving (Show, Eq)
+
+instance Monad m => EncodeM m JITSymbolFlags FFI.JITSymbolFlags where
+  encodeM f = return $ foldr1 (.|.) [
+      if a f
+         then b
+         else 0
+    | (a,b) <- [
+          (jitSymbolWeak, FFI.jitSymbolFlagsWeak),
+          (jitSymbolCommon, FFI.jitSymbolFlagsCommon),
+          (jitSymbolAbsolute, FFI.jitSymbolFlagsAbsolute),
+          (jitSymbolExported, FFI.jitSymbolFlagsExported),
+          (jitSymbolCallable, FFI.jitSymbolFlagsCallable),
+          (jitSymbolMaterializationSideEffectsOnly, FFI.jitSymbolFlagsMaterializationSideEffectsOnly)
+        ]
+    ]
+
+instance Monad m => DecodeM m JITSymbolFlags FFI.JITSymbolFlags where
+  decodeM f =
+    return $ JITSymbolFlags {
+      jitSymbolWeak = FFI.jitSymbolFlagsWeak .&. f /= 0,
+      jitSymbolCommon = FFI.jitSymbolFlagsCommon .&. f /= 0,
+      jitSymbolAbsolute = FFI.jitSymbolFlagsAbsolute .&. f /= 0,
+      jitSymbolExported = FFI.jitSymbolFlagsExported .&. f /= 0,
+      jitSymbolCallable = FFI.jitSymbolFlagsCallable .&. f /= 0,
+      jitSymbolMaterializationSideEffectsOnly = FFI.jitSymbolFlagsMaterializationSideEffectsOnly .&. f /= 0
+    }
+
+instance Monad m => EncodeM m MangledSymbol (Ptr FFI.SymbolStringPtr) where
+  encodeM (MangledSymbol p) = return p
+
+instance (Monad m, MonadIO m, MonadAnyCont IO m) => EncodeM m JITSymbol (Ptr FFI.JITEvaluatedSymbol) where
+  encodeM (JITSymbol addr flags) = do
+    flags' <- encodeM flags
+    anyContToM $ bracket
+      (FFI.createJITEvaluatedSymbol (FFI.TargetAddress $ fromIntegral addr) flags')
+      FFI.disposeJITEvaluatedSymbol
+
+instance (MonadIO m, MonadAnyCont IO m) =>
+         DecodeM m (Either JITSymbolError JITSymbol) (Ptr FFI.ExpectedJITEvaluatedSymbol) where
+  decodeM expectedSym = do
+    errMsg <- alloca
+    FFI.TargetAddress addr <- liftIO $ FFI.getExpectedSymbolAddress expectedSym errMsg
+    rawFlags <- liftIO (FFI.getExpectedSymbolFlags expectedSym)
+    if addr == 0 || (rawFlags .&. FFI.jitSymbolFlagsHasError /= 0)
+      then do
+        errMsg <- decodeM errMsg
+        pure (Left (JITSymbolError errMsg))
+      else do
+        flags <- decodeM rawFlags
+        pure (Right (JITSymbol (fromIntegral addr) flags))
+
+--------------------------------------------------------------------------------
+-- JITDylib
+--------------------------------------------------------------------------------
+
+newtype JITDylib = JITDylib (Ptr FFI.JITDylib)
+
+-- | Create a new 'JITDylib' with the given name.
+createJITDylib :: ExecutionSession -> ShortByteString -> IO JITDylib
+createJITDylib (ExecutionSession es _) name =
+  SBS.useAsCString name $ fmap JITDylib . FFI.createJITDylib es
+
+-- NB: JITDylib unloading is WIP (at least according to some old-looking docs)
+
+-- | Adds a 'JITDylib' definition generator that looks up missing symbols in
+-- the namespace of the current process.
+addDynamicLibrarySearchGeneratorForCurrentProcess :: IRLayer l => l -> JITDylib -> IO ()
+addDynamicLibrarySearchGeneratorForCurrentProcess compileLayer (JITDylib dylib) =
+  FFI.addDynamicLibrarySearchGeneratorForCurrentProcess dylib (getDataLayout compileLayer)
+
+-- | Adds a 'JITDylib' definition generator that looks up missing symbols in
+-- the namespace of a shared library located at the specified 'FilePath'.
+addDynamicLibrarySearchGenerator :: IRLayer l => l -> JITDylib -> FilePath -> IO ()
+addDynamicLibrarySearchGenerator compileLayer (JITDylib dylib) s = withCString s $ \cStr ->
+  FFI.addDynamicLibrarySearchGenerator dylib (getDataLayout compileLayer) cStr
+
+defineAbsoluteSymbols :: JITDylib -> [(MangledSymbol, JITSymbol)] -> IO ()
+defineAbsoluteSymbols (JITDylib dylib) symList =
+  runAnyContT' return $ do
+    (nsyms, symStrPtrPtr) :: (CUInt, Ptr (Ptr FFI.SymbolStringPtr)) <- encodeM symNames
+    (_, symValPtrPtr) :: (CUInt, Ptr (Ptr FFI.JITEvaluatedSymbol)) <- encodeM symVals
+    liftIO $ FFI.defineAbsoluteSymbols dylib nsyms symStrPtrPtr symValPtrPtr
+  where (symNames, symVals) = unzip symList
+
+-- | Looks up an (unmangled) symbol name in the given 'JITDylib'.
+--
+-- The symbol is expected to have been added to the 'JITDylib' by the same 'IRLayer'
+-- as specified in this function. Using a different 'IRLayer' can cause the lookup
+-- to fail due to differences in mangling schemes.
+lookupSymbol :: IRLayer l => ExecutionSession -> l -> JITDylib -> ShortByteString -> IO (Either JITSymbolError JITSymbol)
+lookupSymbol (ExecutionSession es _) irl (JITDylib dylib) name = SBS.useAsCString name $ \nameStr ->
+  runAnyContT' return $ do
+    symbol <- anyContToM $ bracket
+      (FFI.lookupSymbol es dylib (getMangler irl) nameStr) FFI.disposeExpectedJITEvaluatedSymbol
+    decodeM symbol
+
+--------------------------------------------------------------------------------
+-- ThreadSafeContext
+--------------------------------------------------------------------------------
+
+newtype ThreadSafeContext = ThreadSafeContext (Ptr FFI.ThreadSafeContext)
+
+-- | Create a 'ThreadSafeContext'
+createThreadSafeContext :: IO ThreadSafeContext
+createThreadSafeContext = ThreadSafeContext <$> FFI.createThreadSafeContext
+
+-- | Dispose of a 'ThreadSafeContext'
+disposeThreadSafeContext :: ThreadSafeContext -> IO ()
+disposeThreadSafeContext (ThreadSafeContext ctx) = FFI.disposeThreadSafeContext ctx
+
+-- | 'bracket'-style wrapper around 'createThreadSafeContext'
+-- and 'disposeThreadSafeContext'.
+withThreadSafeContext :: (ThreadSafeContext -> IO a) -> IO a
+withThreadSafeContext = bracket createThreadSafeContext disposeThreadSafeContext
+
+--------------------------------------------------------------------------------
+-- ThreadSafeModule
+--------------------------------------------------------------------------------
+
+newtype ThreadSafeModule = ThreadSafeModule (Ptr FFI.ThreadSafeModule)
+
+-- | Create a 'ThreadSafeModule' with the same content as the input 'Module'.
+--
+-- The module will get cloned into a fresh LLVM context. The lifetime of the
+-- new context is bound to the lifetime of the returned 'ThreadSafeModule'.
+cloneAsThreadSafeModule :: Module -> IO ThreadSafeModule
+cloneAsThreadSafeModule m = do
+  mPtr <- readModule m
+  ThreadSafeModule <$> FFI.cloneAsThreadSafeModule mPtr
+
+-- | Dispose of a 'ThreadSafeModule'.
+disposeThreadSafeModule :: ThreadSafeModule -> IO ()
+disposeThreadSafeModule (ThreadSafeModule m) = FFI.disposeThreadSafeModule m
+
+-- | 'bracket'-style wrapper around 'cloneAsThreadSafeModule'
+-- and 'disposeThreadSafeModule'.
+withClonedThreadSafeModule :: Module -> (ThreadSafeModule -> IO a) -> IO a
+withClonedThreadSafeModule m = bracket (cloneAsThreadSafeModule m) disposeThreadSafeModule
+
+--------------------------------------------------------------------------------
+-- ObjectLayer + RTDyldObjectLinkingLayer
+--------------------------------------------------------------------------------
+
+-- | A type class implemented by the different OrcJIT object layers.
+--
+-- See e.g. 'RTDyldObjectLinkingLayer'.
+class ObjectLayer l where
+  getObjectLayer :: l -> Ptr FFI.ObjectLayer
+
+
+data RTDyldObjectLinkingLayer = RTDyldObjectLinkingLayer !(Ptr FFI.ObjectLayer)
+
+instance ObjectLayer RTDyldObjectLinkingLayer where
+  getObjectLayer (RTDyldObjectLinkingLayer ol) = ol
+
+-- | Create a new 'RTDyldObjectLinkingLayer'.
+--
+-- The layer will get automatically disposed along with its ExecutionSession.
+createRTDyldObjectLinkingLayer :: ExecutionSession -> IO RTDyldObjectLinkingLayer
+createRTDyldObjectLinkingLayer (ExecutionSession es cleanups) = do
+  ol <- FFI.createRTDyldObjectLinkingLayer es
+  modifyIORef' cleanups (FFI.disposeObjectLayer ol :)
+  return $ RTDyldObjectLinkingLayer ol
+
+data ObjectLinkingLayer = ObjectLinkingLayer !(Ptr FFI.ObjectLayer)
+
+instance ObjectLayer ObjectLinkingLayer where
+  getObjectLayer (ObjectLinkingLayer ol) = ol
+
+createObjectLinkingLayer :: ExecutionSession -> IO ObjectLinkingLayer
+createObjectLinkingLayer (ExecutionSession es cleanups) = do
+  ol <- FFI.createObjectLinkingLayer es
+  modifyIORef' cleanups (FFI.disposeObjectLayer ol :)
+  return $ ObjectLinkingLayer ol
+
+addObjectFile :: ObjectLayer l => l -> JITDylib -> FilePath -> IO ()
+addObjectFile ol (JITDylib dylib) path = do
+  withCString path $ \cStr ->
+    FFI.objectLayerAddObjectFile (getObjectLayer ol) dylib cStr
+
+--------------------------------------------------------------------------------
+-- IRLayer + IRCompileLayer
+--------------------------------------------------------------------------------
+
+-- | A mangled symbol name. Valid only for as long as the IRLayer that created it.
+newtype MangledSymbol = MangledSymbol (Ptr FFI.SymbolStringPtr)
+
+-- | A type class implemented by the different OrcJIT IR layers.
+--
+-- See e.g. 'IRCompileLayer'.
+class IRLayer l where
+  getIRLayer :: l -> Ptr FFI.IRLayer
+  getDataLayout :: l -> Ptr FFI.DataLayout
+  getMangler :: l -> Ptr FFI.MangleAndInterner
+
+-- | Add a 'Module' to the specified 'JITDylib'.
+--
+-- The specified 'IRLayer' will be responsible for compiling the symbols
+-- present in the module. The module itself is consumed and __should not be used again__.
+addModule :: IRLayer l => ThreadSafeModule -> JITDylib -> l -> IO ()
+addModule (ThreadSafeModule m) (JITDylib dylib) irl =
+  FFI.irLayerAddModule m dylib (getDataLayout irl) (getIRLayer irl)
+
+mangleSymbol :: IRLayer l => l -> ShortByteString -> IO MangledSymbol
+mangleSymbol irl name = SBS.useAsCString name $ \namePtr ->
+  MangledSymbol <$> FFI.mangleSymbol (getMangler irl) namePtr
+
+disposeMangledSymbol :: MangledSymbol -> IO ()
+disposeMangledSymbol (MangledSymbol symbol) = FFI.disposeMangledSymbol symbol
+
+withMangledSymbol :: IRLayer l => l -> ShortByteString -> (MangledSymbol -> IO a) -> IO a
+withMangledSymbol irl name = bracket (mangleSymbol irl name) disposeMangledSymbol
+
+-- | An IR layer that compiles the symbols in a module eagerly.
+data IRCompileLayer = IRCompileLayer !(Ptr FFI.IRLayer) !(Ptr FFI.DataLayout) !(Ptr FFI.MangleAndInterner)
+
+instance IRLayer IRCompileLayer where
+  getIRLayer    (IRCompileLayer cl _ _) = cl
+  getDataLayout (IRCompileLayer _ dl _) = dl
+  getMangler    (IRCompileLayer _ _ mg) = mg
+
+-- | Create a new 'IRCompileLayer'.
+--
+-- The layer will get automatically disposed along with its ExecutionSession.
+createIRCompileLayer :: ObjectLayer l => ExecutionSession -> l -> TargetMachine -> IO IRCompileLayer
+createIRCompileLayer (ExecutionSession es cleanups) ol (TargetMachine tm) = do
+  dl <- FFI.createTargetDataLayout tm
+  modifyIORef' cleanups (FFI.disposeDataLayout dl :)
+  mg <- FFI.createMangleAndInterner es dl
+  modifyIORef' cleanups (FFI.disposeMangleAndInterner mg :)
+  cl <- FFI.createIRCompileLayer es (getObjectLayer ol) tm
+  modifyIORef' cleanups (FFI.disposeIRLayer cl :)
+  return $ IRCompileLayer cl dl mg
diff --git a/src/LLVM/Internal/PassManager.hs b/src/LLVM/Internal/PassManager.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/PassManager.hs
@@ -0,0 +1,153 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses,
+  CPP
+  #-}
+module LLVM.Internal.PassManager where
+
+import LLVM.Prelude
+
+import qualified Language.Haskell.TH as TH
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+
+import qualified Data.ByteString.Short as ByteString
+
+import Foreign.C (CString)
+import Foreign.Ptr
+import GHC.Stack
+
+import qualified LLVM.Internal.FFI.PassManager as FFI
+import qualified LLVM.Internal.FFI.Transforms as FFI
+
+import LLVM.Exception
+import LLVM.Internal.Module
+import LLVM.Internal.Target
+import LLVM.Internal.Coding
+import LLVM.Transforms
+
+import LLVM.AST.DataLayout
+
+-- | <http://llvm.org/doxygen/classllvm_1_1PassManager.html>
+-- Note: a PassManager does substantive behind-the-scenes work, arranging for the
+-- results of various analyses to be available as needed by transform passes, shared
+-- as possible.
+newtype PassManager = PassManager (Ptr FFI.PassManager)
+
+-- | There are different ways to get a 'PassManager'. This type embodies them.
+data PassSetSpec
+  -- | a 'PassSetSpec' is a lower-level, detailed specification of a set of passes. It
+  -- allows fine-grained control of what passes are to be run when, and the specification
+  -- of passes not available through 'CuratedPassSetSpec'.
+  = PassSetSpec {
+      transforms :: [Pass],
+      dataLayout :: Maybe DataLayout,
+      targetLibraryInfo :: Maybe TargetLibraryInfo,
+      targetMachine :: Maybe TargetMachine
+    }
+  -- | This type is a high-level specification of a set of passes. It uses the same
+  -- collection of passes chosen by the LLVM team in the command line tool 'opt'.  The fields
+  -- of this spec are much like typical compiler command-line flags - e.g. -O\<n\>, etc.
+  | CuratedPassSetSpec {
+      optLevel :: Maybe Word,
+      sizeLevel :: Maybe Word,
+      unitAtATime :: Maybe Bool,
+      simplifyLibCalls :: Maybe Bool,
+      loopVectorize :: Maybe Bool,
+      superwordLevelParallelismVectorize :: Maybe Bool,
+      useInlinerWithThreshold :: Maybe Word,
+      dataLayout :: Maybe DataLayout,
+      targetLibraryInfo :: Maybe TargetLibraryInfo,
+      targetMachine :: Maybe TargetMachine
+    }
+
+-- | Helper to make a curated 'PassSetSpec'
+defaultCuratedPassSetSpec :: PassSetSpec
+defaultCuratedPassSetSpec = CuratedPassSetSpec {
+  optLevel = Nothing,
+  sizeLevel = Nothing,
+  unitAtATime = Nothing,
+  simplifyLibCalls = Nothing,
+  loopVectorize = Nothing,
+  superwordLevelParallelismVectorize = Nothing,
+  useInlinerWithThreshold = Nothing,
+  dataLayout = Nothing,
+  targetLibraryInfo = Nothing,
+  targetMachine = Nothing
+}
+
+-- | an empty 'PassSetSpec'
+defaultPassSetSpec :: PassSetSpec
+defaultPassSetSpec = PassSetSpec {
+  transforms = [],
+  dataLayout = Nothing,
+  targetLibraryInfo = Nothing,
+  targetMachine = Nothing
+}
+
+instance (Monad m, MonadThrow m, MonadAnyCont IO m) => EncodeM m GCOVVersion CString where
+  encodeM (GCOVVersion cs)
+    | ByteString.length cs == 4 = encodeM cs
+    | otherwise = throwM (EncodeException "GCOVVersion should consist of exactly 4 characters")
+
+createPassManager :: HasCallStack => PassSetSpec -> IO (Ptr FFI.PassManager)
+createPassManager pss = runAnyContT' return $ do
+  pm <- liftIO $ FFI.createPassManager
+  forM_ (targetLibraryInfo pss) $ \(TargetLibraryInfo tli) -> do
+    liftIO $ FFI.addTargetLibraryInfoPass pm tli
+  forM_ (targetMachine pss) $ \(TargetMachine tm) -> liftIO $ FFI.addAnalysisPasses tm pm
+  case pss of
+    s@CuratedPassSetSpec {} -> liftIO $ do
+      bracket FFI.passManagerBuilderCreate FFI.passManagerBuilderDispose $ \b -> do
+        let handleOption g m = forM_ (m s) (g b <=< encodeM) 
+        handleOption FFI.passManagerBuilderSetOptLevel optLevel
+        handleOption FFI.passManagerBuilderSetSizeLevel sizeLevel
+        handleOption FFI.passManagerBuilderSetDisableUnitAtATime (liftM not . unitAtATime)
+        handleOption FFI.passManagerBuilderSetDisableSimplifyLibCalls (liftM not . simplifyLibCalls)
+        handleOption FFI.passManagerBuilderUseInlinerWithThreshold useInlinerWithThreshold
+        handleOption FFI.passManagerBuilderSetLoopVectorize loopVectorize
+        handleOption FFI.passManagerBuilderSetSuperwordLevelParallelismVectorize superwordLevelParallelismVectorize
+        FFI.passManagerBuilderPopulateModulePassManager b pm
+    PassSetSpec ps _ _ tm' -> do
+      let tm = maybe nullPtr (\(TargetMachine tm) -> tm) tm'
+      forM_ ps $ \p -> $(
+        do
+#if __GLASGOW_HASKELL__ < 800
+          TH.TyConI (TH.DataD _ _ _ cons _) <- TH.reify ''Pass
+#else
+          TH.TyConI (TH.DataD _ _ _ _ cons _) <- TH.reify ''Pass
+#endif
+          TH.caseE [| p |] $ flip map cons $ \con -> do
+            let
+              (n, fns) = case con of
+                            TH.RecC n fs -> (n, [ TH.nameBase fn | (fn, _, _) <- fs ])
+                            TH.NormalC n [] -> (n, [])
+                            _ -> error "pass descriptor constructors with fields need to be records"
+              actions = 
+                [ TH.bindS (TH.varP . TH.mkName $ fn) [| encodeM $(TH.dyn fn) |] | fn <- fns ]
+                ++ [
+                 TH.noBindS [|
+                   liftIO $(
+                     foldl1 TH.appE
+                     (map TH.dyn $
+                        ["FFI.add" ++ TH.nameBase n ++ "Pass", "pm"]
+                        ++ ["tm" | FFI.needsTargetMachine (TH.nameBase n)]
+                        ++ fns)
+                    )
+                   |]
+                 ]
+            TH.match (TH.conP n $ map (TH.varP . TH.mkName) fns) (TH.normalB (TH.doE actions)) []
+       )
+  return pm
+
+-- | bracket the creation of a 'PassManager'
+withPassManager :: PassSetSpec -> (PassManager -> IO a) -> IO a
+withPassManager s = bracket (createPassManager s) FFI.disposePassManager . (. PassManager)
+
+-- | run the passes in a 'PassManager' on a 'Module', modifying the 'Module'.
+runPassManager :: PassManager -> Module -> IO Bool
+runPassManager (PassManager p) m = do
+  m' <- readModule m
+  toEnum . fromIntegral <$> FFI.runPassManager p m'
diff --git a/src/LLVM/Internal/RMWOperation.hs b/src/LLVM/Internal/RMWOperation.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/RMWOperation.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.RMWOperation where
+
+import LLVM.AST.RMWOperation
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Coding
+
+genCodingInstance [t| RMWOperation |] ''FFI.RMWOperation [
+  (FFI.rmwOperationXchg, Xchg),
+  (FFI.rmwOperationAdd, Add),
+  (FFI.rmwOperationSub, Sub),
+  (FFI.rmwOperationAnd, And),
+  (FFI.rmwOperationNand, Nand),
+  (FFI.rmwOperationOr, Or),
+  (FFI.rmwOperationXor, Xor),
+  (FFI.rmwOperationMax, Max),
+  (FFI.rmwOperationMin, Min),
+  (FFI.rmwOperationUMax, UMax),
+  (FFI.rmwOperationUMin, UMin),
+  (FFI.rmwOperationFAdd, FAdd),
+  (FFI.rmwOperationFSub, FSub)
+ ]
+
diff --git a/src/LLVM/Internal/RawOStream.hs b/src/LLVM/Internal/RawOStream.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/RawOStream.hs
@@ -0,0 +1,67 @@
+module LLVM.Internal.RawOStream where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+
+import Data.IORef
+import Foreign.C
+import Foreign.Ptr
+
+import LLVM.Exception
+
+import qualified LLVM.Internal.FFI.RawOStream as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+
+-- May throw 'FdStreamException'.
+withFileRawOStream ::
+  (MonadThrow m, MonadIO m, MonadAnyCont IO m)
+  => String
+  -> Bool
+  -> Bool
+  -> (Ptr FFI.RawOStream -> IO ())
+  -> m ()
+withFileRawOStream path excl text c =
+  withFileRawPWriteStream path excl text (c . FFI.upCast)
+
+-- May throw 'FdStreamException'.
+withFileRawPWriteStream ::
+  (MonadThrow m, MonadIO m, MonadAnyCont IO m)
+  => String
+  -> Bool
+  -> Bool
+  -> (Ptr FFI.RawPWriteStream -> IO ())
+  -> m ()
+withFileRawPWriteStream path excl text c = do
+  path <- encodeM path
+  excl <- encodeM excl
+  text <- encodeM text
+  msgPtr <- alloca
+  succeeded <- decodeM =<< (liftIO $ FFI.withFileRawPWriteStream path excl text msgPtr c)
+  unless succeeded $ do
+    s <- decodeM msgPtr
+    throwM $ FdStreamException s
+
+withBufferRawOStream ::
+  (MonadIO m, DecodeM IO a (Ptr CChar, CSize))
+  => (Ptr FFI.RawOStream -> IO ())
+  -> m a
+withBufferRawOStream c = withBufferRawPWriteStream (c . FFI.upCast)
+
+withBufferRawPWriteStream ::
+  (MonadIO m, DecodeM IO a (Ptr CChar, CSize))
+  => (Ptr FFI.RawPWriteStream -> IO ())
+  -> m a
+withBufferRawPWriteStream c = liftIO $ do
+  resultRef <- newIORef undefined
+  let saveBuffer :: Ptr CChar -> CSize -> IO ()
+      saveBuffer start size = do
+        r <- decodeM (start, size)
+        writeIORef resultRef r
+  FFI.withBufferRawPWriteStream saveBuffer c
+  readIORef resultRef
diff --git a/src/LLVM/Internal/String.hs b/src/LLVM/Internal/String.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/String.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE
+  MultiParamTypeClasses,
+  UndecidableInstances
+  #-}
+module LLVM.Internal.String where
+
+import LLVM.Prelude
+
+import Control.Arrow
+import Control.Monad.AnyCont
+import Control.Monad.IO.Class
+import Control.Exception (finally)
+import Foreign.C (CString, CChar)
+import Foreign.Ptr
+import Foreign.Storable (Storable)
+import Foreign.Marshal.Alloc as F.M (alloca, free)
+
+import LLVM.Internal.FFI.LLVMCTypes
+
+import LLVM.Internal.Coding
+
+import qualified Data.ByteString as BS
+import qualified LLVM.Internal.FFI.ShortByteString as SBS
+import qualified Data.ByteString.Unsafe as BS
+import qualified Data.ByteString.UTF8 as BSUTF8
+
+newtype UTF8ByteString = UTF8ByteString { utf8Bytes :: BS.ByteString }
+
+instance (Monad e) => EncodeM e String UTF8ByteString where
+  encodeM = return . UTF8ByteString . BSUTF8.fromString
+
+instance (Monad d) => DecodeM d String UTF8ByteString where
+  decodeM = return . BSUTF8.toString . utf8Bytes
+
+instance (MonadAnyCont IO e) => EncodeM e String CString where
+  encodeM s = anyContToM (BS.unsafeUseAsCString . utf8Bytes =<< encodeM (s ++ "\0"))
+
+instance (MonadAnyCont IO e) => EncodeM e ByteString CString where
+  encodeM s = anyContToM (BS.useAsCString s)
+
+instance (MonadAnyCont IO e) => EncodeM e ShortByteString CString where
+  encodeM s = anyContToM (SBS.useAsCString s)
+
+instance (Integral i, MonadAnyCont IO e) => EncodeM e String (Ptr CChar, i) where
+  encodeM s = anyContToM ((. (. second fromIntegral)) $ BS.useAsCStringLen . utf8Bytes =<< encodeM s)
+
+instance (Integral i, MonadAnyCont IO e) => EncodeM e ByteString (Ptr CChar, i) where
+  encodeM s =
+    anyContToM (\cont -> BS.useAsCStringLen s (\(ptr, len) -> cont (ptr, fromIntegral len)))
+
+instance (Integral i, MonadAnyCont IO e) => EncodeM e ShortByteString (Ptr CChar, i) where
+  encodeM s =
+    anyContToM (\cont -> SBS.useAsCStringLen s (\(ptr, len) -> cont (ptr, fromIntegral len)))
+
+instance (MonadIO d) => DecodeM d String CString where
+  decodeM = decodeM . UTF8ByteString <=< liftIO . BS.packCString
+
+instance (MonadIO d) => DecodeM d ByteString CString where
+  decodeM = liftIO . BS.packCString
+
+instance (MonadIO d) => DecodeM d ShortByteString CString where
+  decodeM = liftIO . SBS.packCString
+
+instance (MonadIO d) => DecodeM d String (OwnerTransfered CString) where
+  decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s)
+
+instance (MonadIO d) => DecodeM d ByteString (OwnerTransfered CString) where
+  decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s)
+
+instance (MonadIO d) => DecodeM d ShortByteString (OwnerTransfered CString) where
+  decodeM (OwnerTransfered s) = liftIO $ finally (decodeM s) (free s)
+instance (MonadIO d, DecodeM IO s (OwnerTransfered CString)) =>DecodeM d s (Ptr (OwnerTransfered CString)) where
+  decodeM = liftIO . decodeM <=< peek
+
+instance (Integral i, MonadIO d) => DecodeM d String (Ptr CChar, i) where
+  decodeM = decodeM . UTF8ByteString <=< liftIO . BS.packCStringLen . second fromIntegral
+
+instance (Integral i, MonadIO d) => DecodeM d BS.ByteString (Ptr CChar, i) where
+  decodeM = liftIO . BS.packCStringLen . second fromIntegral
+
+instance (Integral i, MonadIO d) => DecodeM d ShortByteString (Ptr CChar, i) where
+  decodeM = liftIO . SBS.packCStringLen . second fromIntegral
+
+instance (Integral i, Storable i, MonadIO d, DecodeM d s (CString, i)) => DecodeM d s (Ptr i -> IO CString) where
+  decodeM f = decodeM =<< (liftIO $ F.M.alloca $ \p -> (,) `liftM` f p `ap` peek p)
+
+instance (Monad e, EncodeM e String c) => EncodeM e (Maybe String) (NothingAsEmptyString c) where
+  encodeM = liftM NothingAsEmptyString . encodeM . fromMaybe ""
+  
diff --git a/src/LLVM/Internal/TailCallKind.hs b/src/LLVM/Internal/TailCallKind.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/TailCallKind.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE
+  TemplateHaskell,
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.TailCallKind where
+
+import LLVM.Prelude
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+import LLVM.Internal.Coding
+import qualified LLVM.AST as A
+
+genCodingInstance [t| Maybe A.TailCallKind |] ''FFI.TailCallKind [
+  (FFI.tailCallKindNone, Nothing),
+  (FFI.tailCallKindTail, Just A.Tail),
+  (FFI.tailCallKindMustTail, Just A.MustTail),
+  (FFI.tailCallKindNoTail, Just A.NoTail)
+ ]
diff --git a/src/LLVM/Internal/Target.hs b/src/LLVM/Internal/Target.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Target.hs
@@ -0,0 +1,470 @@
+{-# LANGUAGE CPP                   #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE RecordWildCards       #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE UndecidableInstances  #-}
+
+module LLVM.Internal.Target where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Except
+
+import Data.Attoparsec.ByteString
+import Data.Attoparsec.ByteString.Char8
+import Data.Char
+import Data.Map (Map)
+import Foreign.C.String
+import Foreign.Ptr
+import qualified Data.ByteString as ByteString
+import qualified Data.Map as Map
+#if __GLASGOW_HASKELL__ < 808
+import Control.Monad.Fail (MonadFail)
+#endif
+
+import LLVM.Internal.Coding
+import LLVM.Internal.String ()
+import LLVM.Internal.LibraryFunction
+import LLVM.DataLayout
+import LLVM.Exception
+
+import LLVM.AST.DataLayout
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import qualified LLVM.Internal.FFI.Target as FFI
+
+import qualified LLVM.Relocation as Reloc
+import qualified LLVM.Target.Options as TO
+import qualified LLVM.CodeModel as CodeModel
+import qualified LLVM.CodeGenOpt as CodeGenOpt
+
+genCodingInstance [t| Reloc.Model |] ''FFI.RelocModel [
+  (FFI.relocModelDefault, Reloc.Default),
+  (FFI.relocModelStatic, Reloc.Static),
+  (FFI.relocModelPIC, Reloc.PIC),
+  (FFI.relocModelDynamicNoPic, Reloc.DynamicNoPIC)
+ ]
+
+genCodingInstance [t| CodeModel.Model |] ''FFI.CodeModel [
+  (FFI.codeModelDefault,CodeModel.Default),
+  (FFI.codeModelJITDefault, CodeModel.JITDefault),
+  (FFI.codeModelSmall, CodeModel.Small),
+  (FFI.codeModelKernel, CodeModel.Kernel),
+  (FFI.codeModelMedium, CodeModel.Medium),
+  (FFI.codeModelLarge, CodeModel.Large)
+ ]
+
+genCodingInstance [t| CodeGenOpt.Level |] ''FFI.CodeGenOptLevel [
+  (FFI.codeGenOptLevelNone, CodeGenOpt.None),
+  (FFI.codeGenOptLevelLess, CodeGenOpt.Less),
+  (FFI.codeGenOptLevelDefault, CodeGenOpt.Default),
+  (FFI.codeGenOptLevelAggressive, CodeGenOpt.Aggressive)
+ ]
+
+genCodingInstance [t| TO.FloatABI |] ''FFI.FloatABIType [
+  (FFI.floatABIDefault, TO.FloatABIDefault),
+  (FFI.floatABISoft, TO.FloatABISoft),
+  (FFI.floatABIHard, TO.FloatABIHard)
+ ]
+
+genCodingInstance [t| TO.FloatingPointOperationFusionMode |] ''FFI.FPOpFusionMode [
+  (FFI.fpOpFusionModeFast, TO.FloatingPointOperationFusionFast),
+  (FFI.fpOpFusionModeStandard, TO.FloatingPointOperationFusionStandard),
+  (FFI.fpOpFusionModeStrict, TO.FloatingPointOperationFusionStrict)
+ ]
+
+genCodingInstance[t| TO.DebugCompressionType |] ''FFI.DebugCompressionType [
+  (FFI.debugCompressionTypeNone, TO.CompressNone),
+  (FFI.debugCompressionTypeGNU, TO.CompressGNU),
+  (FFI.debugCompressionTypeZ, TO.CompressZ)
+  ]
+
+genCodingInstance[t| TO.ThreadModel |] ''FFI.ThreadModel [
+  (FFI.threadModelPOSIX, TO.ThreadModelPOSIX),
+  (FFI.threadModelSingle, TO.ThreadModelSingle)
+ ]
+
+genCodingInstance[t| TO.EABIVersion |] ''FFI.EABI [
+  (FFI.eabiVersionUnknown, TO.EABIVersionUnknown),
+  (FFI.eabiVersionDefault, TO.EABIVersionDefault),
+  (FFI.eabiVersionEABI4, TO.EABIVersion4),
+  (FFI.eabiVersionEABI5, TO.EABIVersion5),
+  (FFI.eabiVersionGNU, TO.EABIVersionGNU)
+ ]
+
+genCodingInstance[t| TO.DebuggerKind |] ''FFI.DebuggerKind [
+  (FFI.debuggerKindDefault, TO.DebuggerDefault),
+  (FFI.debuggerKindGDB, TO.DebuggerGDB),
+  (FFI.debuggerKindLLDB, TO.DebuggerLLDB),
+  (FFI.debuggerKindSCE, TO.DebuggerSCE)
+ ]
+
+genCodingInstance[t| TO.FloatingPointDenormalMode |] ''FFI.FPDenormalMode [
+  (FFI.fpDenormalModeIEEE, TO.FloatingPointDenormalIEEE),
+  (FFI.fpDenormalModePreserveSign, TO.FloatingPointDenormalPreserveSign),
+  (FFI.fpDenormalModePositiveZero, TO.FloatingPointDenormalPositiveZero)
+ ]
+
+genCodingInstance[t| TO.ExceptionHandling |] ''FFI.ExceptionHandling [
+  (FFI.exceptionHandlingNone, TO.ExceptionHandlingNone),
+  (FFI.exceptionHandlingDwarfCFI, TO.ExceptionHandlingDwarfCFI),
+  (FFI.exceptionHandlingSjLj, TO.ExceptionHandlingSjLj),
+  (FFI.exceptionHandlingARM, TO.ExceptionHandlingARM),
+  (FFI.exceptionHandlingWinEH, TO.ExceptionHandlingWinEH)
+ ]
+
+-- | <http://llvm.org/doxygen/classllvm_1_1Target.html>
+newtype Target = Target (Ptr FFI.Target)
+
+-- | e.g. an instruction set extension
+newtype CPUFeature = CPUFeature ByteString
+  deriving (Eq, Ord, Read, Show)
+
+instance EncodeM e ByteString es => EncodeM e (Map CPUFeature Bool) es where
+  encodeM = encodeM . ByteString.intercalate "," . map (\(CPUFeature f, enabled) -> (if enabled then "+" else "-") <> f) . Map.toList
+
+instance (MonadFail d, DecodeM d ByteString es) => DecodeM d (Map CPUFeature Bool) es where
+  decodeM es = do
+    s <- decodeM es
+    let flag = do
+          en <- choice [char8 '-' >> return False, char8 '+' >> return True]
+          s <- ByteString.pack <$> many1 (notWord8 (fromIntegral (ord ',')))
+          return (CPUFeature s, en)
+        features = liftM Map.fromList (flag `sepBy` (char8 ','))
+    case parseOnly (features <* endOfInput) s of
+      Right features -> return features
+      Left err -> fail ("failure to parse CPUFeature string: " <> err)
+
+-- | Find a 'Target' given an architecture and/or a \"triple\".
+-- | <http://llvm.org/doxygen/structllvm_1_1TargetRegistry.html#a3105b45e546c9cc3cf78d0f2ec18ad89>
+-- | Be sure to run either 'initializeAllTargets' or
+-- 'initializeNativeTarget' before expecting this to succeed,
+-- depending on what target(s) you want to use. May throw
+-- 'LookupTargetException' if no target is found.
+lookupTarget ::
+  Maybe ShortByteString -- ^ arch
+  -> ShortByteString -- ^ \"triple\" - e.g. x86_64-unknown-linux-gnu
+  -> IO (Target, ShortByteString)
+lookupTarget arch triple = runAnyContT' return $ do
+  cErrorP <- alloca
+  cNewTripleP <- alloca
+  arch <- encodeM (maybe "" id arch)
+  triple <- encodeM triple
+  target <- liftIO $ FFI.lookupTarget arch triple cNewTripleP cErrorP
+  when (target == nullPtr) $ throwM . LookupTargetException =<< decodeM cErrorP
+  liftM (Target target, ) $ decodeM cNewTripleP
+
+-- | <http://llvm.org/doxygen/classllvm_1_1TargetOptions.html>
+newtype TargetOptions = TargetOptions (Ptr FFI.TargetOptions)
+
+newtype MCTargetOptions = MCTargetOptions (Ptr FFI.MCTargetOptions)
+
+-- | bracket creation and destruction of a 'TargetOptions' object
+withTargetOptions :: (TargetOptions -> IO a) -> IO a
+withTargetOptions = bracket FFI.createTargetOptions FFI.disposeTargetOptions . (. TargetOptions)
+
+-- | set all target options
+pokeTargetOptions :: TO.Options -> TargetOptions -> IO ()
+pokeTargetOptions hOpts opts@(TargetOptions cOpts) = do
+  mapM_ (\(c, ha) -> FFI.setTargetOptionFlag cOpts c =<< encodeM (ha hOpts)) [
+    (FFI.targetOptionFlagUnsafeFPMath, TO.unsafeFloatingPointMath),
+    (FFI.targetOptionFlagNoInfsFPMath, TO.noInfinitiesFloatingPointMath),
+    (FFI.targetOptionFlagNoNaNsFPMath, TO.noNaNsFloatingPointMath),
+    (FFI.targetOptionFlagNoTrappingFPMath, TO.noTrappingFloatingPointMath),
+    (FFI.targetOptionFlagNoSignedZerosFPMath, TO.noSignedZeroesFloatingPointMath),
+    (FFI.targetOptionFlagHonorSignDependentRoundingFPMathOption, TO.honorSignDependentRoundingFloatingPointMathOption),
+    (FFI.targetOptionFlagNoZerosInBSS, TO.noZerosInBSS),
+    (FFI.targetOptionFlagGuaranteedTailCallOpt, TO.guaranteedTailCallOptimization),
+    (FFI.targetOptionFlagStackSymbolOrdering, TO.stackSymbolOrdering),
+    (FFI.targetOptionFlagEnableFastISel, TO.enableFastInstructionSelection),
+    (FFI.targetOptionFlagUseInitArray, TO.useInitArray),
+    (FFI.targetOptionFlagDisableIntegratedAS, TO.disableIntegratedAssembler),
+    (FFI.targetOptionFlagRelaxELFRelocations, TO.relaxELFRelocations),
+    (FFI.targetOptionFlagFunctionSections, TO.functionSections),
+    (FFI.targetOptionFlagDataSections, TO.dataSections),
+    (FFI.targetOptionFlagUniqueSectionNames, TO.uniqueSectionNames),
+    (FFI.targetOptionFlagTrapUnreachable, TO.trapUnreachable),
+    (FFI.targetOptionFlagEmulatedTLS, TO.emulatedThreadLocalStorage),
+    (FFI.targetOptionFlagEnableIPRA, TO.enableInterProceduralRegisterAllocation)
+   ]
+  FFI.setStackAlignmentOverride cOpts =<< encodeM (TO.stackAlignmentOverride hOpts)
+  FFI.setFloatABIType cOpts =<< encodeM (TO.floatABIType hOpts)
+  FFI.setAllowFPOpFusion cOpts =<< encodeM (TO.allowFloatingPointOperationFusion hOpts)
+  FFI.setCompressDebugSections cOpts =<< encodeM (TO.compressDebugSections hOpts)
+  FFI.setThreadModel cOpts =<< encodeM (TO.threadModel hOpts)
+  FFI.setEABIVersion cOpts =<< encodeM (TO.eabiVersion hOpts)
+  FFI.setDebuggerTuning cOpts =<< encodeM (TO.debuggerTuning hOpts)
+  FFI.setFPDenormalMode cOpts =<< encodeM (TO.floatingPointDenormalMode hOpts)
+  FFI.setExceptionModel cOpts =<< encodeM (TO.exceptionModel hOpts)
+  pokeMachineCodeOptions (TO.machineCodeOptions hOpts) =<< machineCodeOptions opts
+
+pokeMachineCodeOptions :: TO.MachineCodeOptions -> MCTargetOptions -> IO ()
+pokeMachineCodeOptions hOpts (MCTargetOptions cOpts) =
+  mapM_ (\(c, ha) -> FFI.setMCTargetOptionFlag cOpts c =<< encodeM (ha hOpts)) [
+    (FFI.mcTargetOptionFlagMCRelaxAll, TO.relaxAll),
+    (FFI.mcTargetOptionFlagMCNoExecStack, TO.noExecutableStack),
+    (FFI.mcTargetOptionFlagMCFatalWarnings, TO.fatalWarnings),
+    (FFI.mcTargetOptionFlagMCNoWarn, TO.noWarnings),
+    (FFI.mcTargetOptionFlagMCNoDeprecatedWarn, TO.noDeprecatedWarning),
+    (FFI.mcTargetOptionFlagMCSaveTempLabels, TO.saveTemporaryLabels),
+    (FFI.mcTargetOptionFlagMCUseDwarfDirectory, TO.useDwarfDirectory),
+    (FFI.mcTargetOptionFlagMCIncrementalLinkerCompatible, TO.incrementalLinkerCompatible),
+    (FFI.mcTargetOptionFlagShowMCEncoding, TO.showMachineCodeEncoding),
+    (FFI.mcTargetOptionFlagShowMCInst, TO.showMachineCodeInstructions),
+    (FFI.mcTargetOptionFlagAsmVerbose, TO.verboseAssembly),
+    (FFI.mcTargetOptionFlagPreserveAsmComments, TO.preserveComentsInAssembly)
+   ]
+
+-- | get all target options
+peekTargetOptions :: TargetOptions -> IO TO.Options
+peekTargetOptions opts@(TargetOptions tOpts) = do
+  let gof = decodeM <=< FFI.getTargetOptionsFlag tOpts
+  unsafeFloatingPointMath
+    <- gof FFI.targetOptionFlagUnsafeFPMath
+  noInfinitiesFloatingPointMath
+    <- gof FFI.targetOptionFlagNoInfsFPMath
+  noNaNsFloatingPointMath
+    <- gof FFI.targetOptionFlagNoNaNsFPMath
+  noTrappingFloatingPointMath
+    <- gof FFI.targetOptionFlagNoTrappingFPMath
+  noSignedZeroesFloatingPointMath
+    <- gof FFI.targetOptionFlagNoSignedZerosFPMath
+  honorSignDependentRoundingFloatingPointMathOption
+    <- gof FFI.targetOptionFlagHonorSignDependentRoundingFPMathOption
+  noZerosInBSS
+    <- gof FFI.targetOptionFlagNoZerosInBSS
+  guaranteedTailCallOptimization
+    <- gof FFI.targetOptionFlagGuaranteedTailCallOpt
+  stackSymbolOrdering
+    <- gof FFI.targetOptionFlagStackSymbolOrdering
+  enableFastInstructionSelection
+    <- gof FFI.targetOptionFlagEnableFastISel
+  useInitArray
+    <- gof FFI.targetOptionFlagUseInitArray
+  disableIntegratedAssembler
+    <- gof FFI.targetOptionFlagDisableIntegratedAS
+  compressDebugSections <- decodeM =<< FFI.getCompressDebugSections tOpts
+  relaxELFRelocations
+    <- gof FFI.targetOptionFlagRelaxELFRelocations
+  functionSections
+    <- gof FFI.targetOptionFlagFunctionSections
+  dataSections
+    <- gof FFI.targetOptionFlagDataSections
+  uniqueSectionNames
+    <- gof FFI.targetOptionFlagUniqueSectionNames
+  trapUnreachable
+    <- gof FFI.targetOptionFlagTrapUnreachable
+  emulatedThreadLocalStorage
+    <- gof FFI.targetOptionFlagEmulatedTLS
+  enableInterProceduralRegisterAllocation
+    <- gof FFI.targetOptionFlagEnableIPRA
+  stackAlignmentOverride <- decodeM =<< FFI.getStackAlignmentOverride tOpts
+  floatABIType <- decodeM =<< FFI.getFloatABIType tOpts
+  allowFloatingPointOperationFusion <- decodeM =<< FFI.getAllowFPOpFusion tOpts
+  threadModel <- decodeM =<< FFI.getThreadModel tOpts
+  eabiVersion <- decodeM =<< FFI.getEABIVersion tOpts
+  debuggerTuning <- decodeM =<< FFI.getDebuggerTuning tOpts
+  floatingPointDenormalMode <- decodeM =<< FFI.getFPDenormalMode tOpts
+  exceptionModel <- decodeM =<< FFI.getExceptionModel tOpts
+  machineCodeOptions <- peekMachineCodeOptions =<< machineCodeOptions opts
+  return TO.Options { .. }
+
+-- | get all machine code options
+peekMachineCodeOptions :: MCTargetOptions -> IO TO.MachineCodeOptions
+peekMachineCodeOptions (MCTargetOptions tOpts) = do
+  let gof = decodeM <=< FFI.getMCTargetOptionsFlag tOpts
+  relaxAll
+    <- gof FFI.mcTargetOptionFlagMCRelaxAll
+  noExecutableStack
+    <- gof FFI.mcTargetOptionFlagMCNoExecStack
+  fatalWarnings
+    <- gof FFI.mcTargetOptionFlagMCFatalWarnings
+  noWarnings
+    <- gof FFI.mcTargetOptionFlagMCNoWarn
+  noDeprecatedWarning
+    <- gof FFI.mcTargetOptionFlagMCNoDeprecatedWarn
+  saveTemporaryLabels
+    <- gof FFI.mcTargetOptionFlagMCSaveTempLabels
+  useDwarfDirectory
+    <- gof FFI.mcTargetOptionFlagMCUseDwarfDirectory
+  incrementalLinkerCompatible
+    <- gof FFI.mcTargetOptionFlagMCIncrementalLinkerCompatible
+  showMachineCodeEncoding
+    <- gof FFI.mcTargetOptionFlagShowMCEncoding
+  showMachineCodeInstructions
+    <- gof FFI.mcTargetOptionFlagShowMCInst
+  verboseAssembly
+    <- gof FFI.mcTargetOptionFlagAsmVerbose
+  preserveComentsInAssembly
+    <- gof FFI.mcTargetOptionFlagPreserveAsmComments
+  return TO.MachineCodeOptions { .. }
+
+-- | <http://llvm.org/doxygen/classllvm_1_1TargetMachine.html>
+newtype TargetMachine = TargetMachine (Ptr FFI.TargetMachine)
+
+-- | bracket creation and destruction of a 'TargetMachine'
+withTargetMachine ::
+    Target
+    -> ShortByteString -- ^ triple
+    -> ByteString -- ^ cpu
+    -> Map CPUFeature Bool -- ^ features
+    -> TargetOptions
+    -> Reloc.Model
+    -> CodeModel.Model
+    -> CodeGenOpt.Level
+    -> (TargetMachine -> IO a)
+    -> IO a
+withTargetMachine
+  (Target target)
+  triple
+  cpu
+  features
+  (TargetOptions targetOptions)
+  relocModel
+  codeModel
+  codeGenOptLevel = runAnyContT $ do
+  triple <- encodeM triple
+  cpu <- encodeM cpu
+  features <- encodeM features
+  relocModel <- encodeM relocModel
+  codeModel <- encodeM codeModel
+  codeGenOptLevel <- encodeM codeGenOptLevel
+  anyContToM $ bracket (
+      FFI.createTargetMachine
+         target
+         triple
+         cpu
+         features
+         targetOptions
+         relocModel
+         codeModel
+         codeGenOptLevel
+      )
+      FFI.disposeTargetMachine
+      . (. TargetMachine)
+
+targetMachineOptions :: TargetMachine -> IO TargetOptions
+targetMachineOptions (TargetMachine tm) = TargetOptions <$> FFI.targetMachineOptions tm
+
+machineCodeOptions :: TargetOptions -> IO MCTargetOptions
+machineCodeOptions (TargetOptions to) = MCTargetOptions <$> FFI.machineCodeOptions to
+
+-- | <http://llvm.org/doxygen/classllvm_1_1TargetLowering.html>
+newtype TargetLowering = TargetLowering (Ptr FFI.TargetLowering)
+
+-- | get the 'TargetLowering' of a 'TargetMachine'
+getTargetLowering :: TargetMachine -> IO TargetLowering
+getTargetLowering (TargetMachine _) = TargetLowering <$> error "FIXME: getTargetLowering" -- FFI.getTargetLowering tm
+
+-- | Initialize the native target. This function is called automatically in these Haskell bindings
+-- when creating an 'LLVM.ExecutionEngine.ExecutionEngine' which will require it, and so it should
+-- not be necessary to call it separately.
+initializeNativeTarget :: IO ()
+initializeNativeTarget = do
+  failure <- decodeM =<< liftIO FFI.initializeNativeTarget
+  when failure $ fail "native target initialization failed"
+
+-- | the target triple corresponding to the target machine
+getTargetMachineTriple :: TargetMachine -> IO ShortByteString
+getTargetMachineTriple (TargetMachine m) = decodeM =<< FFI.getTargetMachineTriple m
+
+-- | the default target triple that LLVM has been configured to produce code for
+getDefaultTargetTriple :: IO ShortByteString
+getDefaultTargetTriple = decodeM =<< FFI.getDefaultTargetTriple
+
+-- | a target triple suitable for loading code into the current process
+getProcessTargetTriple :: IO ShortByteString
+getProcessTargetTriple = decodeM =<< FFI.getProcessTargetTriple
+
+-- | the LLVM name for the host CPU
+getHostCPUName :: IO ByteString
+getHostCPUName = decodeM FFI.getHostCPUName
+
+-- | a space-separated list of LLVM feature names supported by the host CPU
+getHostCPUFeatures :: IO (Map CPUFeature Bool)
+getHostCPUFeatures =
+  decodeM =<< FFI.getHostCPUFeatures
+
+-- | 'DataLayout' to use for the given 'TargetMachine'
+getTargetMachineDataLayout :: TargetMachine -> IO DataLayout
+getTargetMachineDataLayout (TargetMachine m) = do
+  dlString <- decodeM =<< FFI.getTargetMachineDataLayout m
+  let Right (Just dl) = runExcept . parseDataLayout BigEndian $ dlString
+  return dl
+
+-- | Initialize all targets so they can be found by 'lookupTarget'
+initializeAllTargets :: IO ()
+initializeAllTargets = FFI.initializeAllTargets
+
+-- | Bracket creation and destruction of a 'TargetMachine' configured for the host.
+--
+-- This function infers and fills the properties of the host machine
+-- (architecture, CPU type, operating system etc.) to construct
+-- a 'TargetMachine' value, but other parameters of 'TargetMachine' (the
+-- code model, relocation model, and optimization level) have to be
+-- provided by the user. For instance, for the JIT-compiled code that you
+-- want to dynamically load you probably want to use the 'Reloc.PIC'
+-- relocation model.
+withHostTargetMachine
+  :: Reloc.Model
+  -> CodeModel.Model
+  -> CodeGenOpt.Level
+  -> (TargetMachine -> IO a) -> IO a
+withHostTargetMachine relocModel codeModel codeGenOpt f = do
+  initializeAllTargets
+  triple <- getProcessTargetTriple
+  cpu <- getHostCPUName
+  features <- getHostCPUFeatures
+  (target, _) <- lookupTarget Nothing triple
+  withTargetOptions $ \options ->
+    withTargetMachine target triple cpu features options relocModel codeModel codeGenOpt f
+
+-- | Like 'withHostTargetMachine', but assumes the default values for the
+-- relocation model, code model, and optimization level ('Reloc.Default',
+-- 'CodeModel.Default', 'CodeGenOpt.Default' respectively).
+--
+-- Note that the 'Reloc.Default' relocation model __is not__ suitable for
+-- JIT compilation; use 'withHostTargetMachine' and 'Reloc.PIC' instead.
+withHostTargetMachineDefault :: (TargetMachine -> IO a) -> IO a
+withHostTargetMachineDefault f = withHostTargetMachine Reloc.Default CodeModel.Default CodeGenOpt.Default f
+
+-- | <http://llvm.org/docs/doxygen/html/classllvm_1_1TargetLibraryInfo.html>
+newtype TargetLibraryInfo = TargetLibraryInfo (Ptr FFI.TargetLibraryInfo)
+
+-- | Look up a 'LibraryFunction' by its standard name
+getLibraryFunction :: TargetLibraryInfo -> ShortByteString -> IO (Maybe LibraryFunction)
+getLibraryFunction (TargetLibraryInfo f) name = runAnyContT' return $ do
+  libFuncP <- alloca :: AnyContT IO (Ptr FFI.LibFunc)
+  name <- (encodeM name :: AnyContT IO CString)
+  r <- decodeM =<< (liftIO $ FFI.getLibFunc f name libFuncP)
+  forM (if r then Just libFuncP else Nothing) $ decodeM <=< peek
+
+-- | Get a the current name to be emitted for a 'LibraryFunction'
+getLibraryFunctionName :: TargetLibraryInfo -> LibraryFunction -> IO ShortByteString
+getLibraryFunctionName (TargetLibraryInfo f) l = runAnyContT' return $ do
+  l <- encodeM l
+  decodeM $ FFI.libFuncGetName f l
+
+-- | Set the name of the function on the target platform that corresponds to funcName
+setLibraryFunctionAvailableWithName ::
+  TargetLibraryInfo
+  -> LibraryFunction
+  -> ShortByteString -- ^ The function name to be emitted
+  -> IO ()
+setLibraryFunctionAvailableWithName (TargetLibraryInfo f) libraryFunction name = runAnyContT' return $ do
+  name <- encodeM name
+  libraryFunction <- encodeM libraryFunction
+  liftIO $ FFI.libFuncSetAvailableWithName f libraryFunction name
+
+-- | look up information about the library functions available on a given platform
+withTargetLibraryInfo ::
+  ShortByteString -- ^ triple
+  -> (TargetLibraryInfo -> IO a)
+  -> IO a
+withTargetLibraryInfo triple f = runAnyContT' return $ do
+  triple <- encodeM triple
+  liftIO $ bracket (FFI.createTargetLibraryInfo triple) FFI.disposeTargetLibraryInfo (f . TargetLibraryInfo)
diff --git a/src/LLVM/Internal/Threading.hs b/src/LLVM/Internal/Threading.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Threading.hs
@@ -0,0 +1,13 @@
+module LLVM.Internal.Threading (
+  isMultithreaded
+  ) where
+
+import LLVM.Prelude
+
+import qualified LLVM.Internal.FFI.Threading as FFI
+
+import LLVM.Internal.Coding
+
+-- | Check if multithreading is enabled in LLVM
+isMultithreaded :: IO Bool
+isMultithreaded = FFI.isMultithreaded >>= decodeM
diff --git a/src/LLVM/Internal/Type.hs b/src/LLVM/Internal/Type.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Type.hs
@@ -0,0 +1,196 @@
+{-# LANGUAGE
+  QuasiQuotes,
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.Type where
+
+import LLVM.Prelude
+
+import Control.Monad.AnyCont
+import Control.Monad.Catch
+import Control.Monad.State
+
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+import LLVM.Internal.FFI.LLVMCTypes (typeKindP)
+import qualified LLVM.Internal.FFI.Type as FFI
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+
+import qualified LLVM.AST as A
+import qualified LLVM.AST.AddrSpace as A
+import LLVM.Exception
+
+import LLVM.Internal.Context
+import LLVM.Internal.Coding
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+
+getStructure :: Ptr FFI.Type -> DecodeAST A.Type
+getStructure t = scopeAnyCont $ do
+  return A.StructureType
+   `ap` (decodeM =<< liftIO (FFI.isPackedStruct t))
+   `ap` do
+       n <- liftIO (FFI.countStructElementTypes t)
+       ts <- allocaArray n
+       liftIO $ FFI.getStructElementTypes t ts
+       decodeM (n, ts)
+
+getStructDefinitions :: DecodeAST [A.Definition]
+getStructDefinitions = do
+  let getStructDefinition t = do
+       opaque <- decodeM =<< liftIO (FFI.structIsOpaque t)
+       if opaque then return Nothing else Just <$> getStructure t
+  flip fix Set.empty $ \continue done -> do
+    t <- takeTypeToDefine
+    flip (maybe (return [])) t $ \t -> do
+      if t `Set.member` done
+        then
+          continue done
+        else
+          return (:)
+            `ap` (return A.TypeDefinition `ap` getTypeName t `ap` getStructDefinition t)
+            `ap` (continue $ Set.insert t done)
+
+isArrayType :: Ptr FFI.Type -> IO Bool
+isArrayType t = do
+  k <- liftIO $ FFI.getTypeKind t
+  return $ k == FFI.typeKindArray
+
+instance Monad m => EncodeM m A.AddrSpace FFI.AddrSpace where
+  encodeM (A.AddrSpace a) = return FFI.AddrSpace `ap` encodeM a
+
+instance Monad m => DecodeM m A.AddrSpace FFI.AddrSpace where
+  decodeM (FFI.AddrSpace a) = return A.AddrSpace `ap` decodeM a
+
+instance EncodeM EncodeAST A.Type (Ptr FFI.Type) where
+  encodeM f = scopeAnyCont $ do
+    Context context <- gets encodeStateContext
+    case f of
+      A.IntegerType bits -> do
+        bits <- encodeM bits
+        liftIO $ FFI.intTypeInContext context bits
+      A.FunctionType returnTypeAST argTypeASTs isVarArg -> do
+        returnType <- encodeM returnTypeAST
+        argTypes <- encodeM argTypeASTs
+        isVarArg <- encodeM isVarArg
+        liftIO $ FFI.functionType returnType argTypes isVarArg
+      A.PointerType elementType addressSpace -> do
+        e <- encodeM elementType
+        a <- encodeM addressSpace
+        liftIO $ FFI.pointerType e a
+      A.VoidType -> liftIO $ FFI.voidTypeInContext context
+      A.FloatingPointType A.HalfFP      -> liftIO $ FFI.halfTypeInContext context
+      A.FloatingPointType A.FloatFP     -> liftIO $ FFI.floatTypeInContext context
+      A.FloatingPointType A.DoubleFP    -> liftIO $ FFI.doubleTypeInContext context
+      A.FloatingPointType A.X86_FP80FP  -> liftIO $ FFI.x86FP80TypeInContext context
+      A.FloatingPointType A.FP128FP     -> liftIO $ FFI.fP128TypeInContext context
+      A.FloatingPointType A.PPC_FP128FP -> liftIO $ FFI.ppcFP128TypeInContext context
+      A.VectorType sz e -> do
+        e <- encodeM e
+        sz <- encodeM sz
+        liftIO $ FFI.vectorType e sz
+      A.ArrayType sz e -> do
+        e <- encodeM e
+        sz <- encodeM sz
+        liftIO $ FFI.arrayType e sz
+      A.StructureType packed ets -> do
+        ets <- encodeM ets
+        packed <- encodeM packed
+        liftIO $ FFI.structTypeInContext context ets packed
+      A.NamedTypeReference n -> lookupNamedType n
+      A.MetadataType -> liftIO $ FFI.metadataTypeInContext context
+      A.TokenType -> liftIO $ FFI.tokenTypeInContext context
+      A.LabelType -> liftIO $ FFI.labelTypeInContext context
+
+instance DecodeM DecodeAST A.Type (Ptr FFI.Type) where
+  decodeM t = scopeAnyCont $ do
+    k <- liftIO $ FFI.getTypeKind t
+    case k of
+      [typeKindP|Void|] -> return A.VoidType
+      [typeKindP|Integer|] -> A.IntegerType <$> (decodeM =<< liftIO (FFI.getIntTypeWidth t))
+      [typeKindP|Function|] ->
+          return A.FunctionType
+               `ap` (decodeM =<< liftIO (FFI.getReturnType t))
+               `ap` (do
+                      n <- liftIO (FFI.countParamTypes t)
+                      ts <- allocaArray n
+                      liftIO $ FFI.getParamTypes t ts
+                      decodeM (n, ts)
+                   )
+               `ap` (decodeM =<< liftIO (FFI.isFunctionVarArg t))
+      [typeKindP|Pointer|] ->
+          return A.PointerType
+             `ap` (decodeM =<< liftIO (FFI.getElementType t))
+             `ap` (decodeM =<< liftIO (FFI.getPointerAddressSpace t))
+      [typeKindP|Half|]      -> return $ A.FloatingPointType A.HalfFP
+      [typeKindP|Float|]     -> return $ A.FloatingPointType A.FloatFP
+      [typeKindP|Double|]    -> return $ A.FloatingPointType A.DoubleFP
+      [typeKindP|FP128|]     -> return $ A.FloatingPointType A.FP128FP
+      [typeKindP|X86_FP80|]  -> return $ A.FloatingPointType A.X86_FP80FP
+      [typeKindP|PPC_FP128|] -> return $ A.FloatingPointType A.PPC_FP128FP
+      [typeKindP|Vector|] ->
+        return A.VectorType
+         `ap` (decodeM =<< liftIO (FFI.getVectorSize t))
+         `ap` (decodeM =<< liftIO (FFI.getElementType t))
+      [typeKindP|Struct|] -> do
+        let ifM c a b = c >>= \x -> if x then a else b
+        ifM (decodeM =<< liftIO (FFI.structIsLiteral t))
+            (getStructure t)
+            (saveNamedType t >> return A.NamedTypeReference `ap` getTypeName t)
+      [typeKindP|Metadata|] -> return A.MetadataType
+      [typeKindP|Array|] ->
+        return A.ArrayType
+         `ap` (decodeM =<< liftIO (FFI.getArrayLength t))
+         `ap` (decodeM =<< liftIO (FFI.getElementType t))
+      [typeKindP|Token|] -> return A.TokenType
+      [typeKindP|Label|] -> return A.LabelType
+      _ -> error $ "unhandled type kind " ++ show k
+
+createNamedType :: A.Name -> EncodeAST (Ptr FFI.Type, Maybe ShortByteString)
+createNamedType n = do
+  Context c <- gets encodeStateContext
+  n <- case n of { A.Name n -> encodeM n; _ -> return nullPtr }
+  renamedName <- alloca
+  t <- liftIO $ FFI.structCreateNamed c n renamedName
+  p <- peek renamedName
+  if p == FFI.OwnerTransfered nullPtr
+    then pure (t, Nothing)
+    else do
+      n' <- decodeM p
+      pure (t, Just n')
+
+renameType :: A.Type -> EncodeAST A.Type
+renameType A.VoidType = pure A.VoidType
+renameType t@(A.IntegerType _) = pure t
+renameType (A.PointerType r a) = fmap (\r' -> A.PointerType r' a) (renameType r)
+renameType t@(A.FloatingPointType _) = pure t
+renameType (A.FunctionType r as varArg) =
+  liftA2
+    (\r' as' -> A.FunctionType r' as' varArg)
+    (renameType r)
+    (traverse renameType as)
+renameType (A.VectorType n t) = A.VectorType n <$> renameType t
+renameType (A.StructureType packed ts) = A.StructureType packed <$> traverse renameType ts
+renameType (A.ArrayType n t) = A.ArrayType n <$> renameType t
+renameType t@(A.NamedTypeReference n) = do
+  renamedTypes <- gets encodeStateRenamedTypes
+  case Map.lookup n renamedTypes of
+    Just n' -> pure (A.NamedTypeReference (A.Name n'))
+    Nothing -> pure t
+renameType A.MetadataType = pure A.MetadataType
+renameType A.LabelType = pure A.LabelType
+renameType A.TokenType = pure A.TokenType
+
+setNamedType :: Ptr FFI.Type -> A.Type -> EncodeAST ()
+setNamedType t (A.StructureType packed ets) = do
+  ets <- encodeM ets
+  packed <- encodeM packed
+  liftIO $ FFI.structSetBody t ets packed
+setNamedType _ ty =
+  throwM
+    (EncodeException
+       ("A type definition requires a structure type but got: " ++ show ty))
diff --git a/src/LLVM/Internal/Value.hs b/src/LLVM/Internal/Value.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Internal/Value.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE
+  MultiParamTypeClasses
+  #-}
+module LLVM.Internal.Value where
+
+import LLVM.Prelude
+
+import Control.Monad.State
+
+import Foreign.Ptr
+
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Value as FFI
+
+import LLVM.Internal.Coding
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.Type () 
+
+import qualified LLVM.AST.Type as A
+
+typeOf :: FFI.DescendentOf FFI.Value v => Ptr v -> DecodeAST A.Type
+typeOf = decodeM <=< liftIO . FFI.typeOf . FFI.upCast
+
diff --git a/src/LLVM/Linking.hs b/src/LLVM/Linking.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Linking.hs
@@ -0,0 +1,7 @@
+-- | Utility functions for resolving external symbols
+module LLVM.Linking
+  ( loadLibraryPermanently
+  , getSymbolAddressInProcess
+  ) where
+
+import LLVM.Internal.Linking
diff --git a/src/LLVM/Module.hs b/src/LLVM/Module.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Module.hs
@@ -0,0 +1,31 @@
+-- | A 'Module' holds a C++ LLVM IR module. 'Module's may be converted to or from strings or Haskell ASTs, or
+-- added to an 'LLVM.ExecutionEngine.ExecutionEngine' and so JIT compiled to get function pointers.
+module LLVM.Module (
+    Module,
+    File(..),
+
+    withModuleFromAST,
+    createModuleFromAST,
+    disposeModule,
+
+    moduleContext,
+    moduleAST,
+
+    withModuleFromLLVMAssembly,
+    moduleLLVMAssembly,
+    writeLLVMAssemblyToFile,
+
+    withModuleFromBitcode,
+    moduleBitcode,
+    writeBitcodeToFile,
+
+    moduleTargetAssembly,
+    writeTargetAssemblyToFile,
+
+    moduleObject,
+    writeObjectToFile,
+
+    linkModules
+  ) where
+
+import LLVM.Internal.Module
diff --git a/src/LLVM/OrcJIT.hs b/src/LLVM/OrcJIT.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/OrcJIT.hs
@@ -0,0 +1,54 @@
+module LLVM.OrcJIT (
+    -- * ExecutionSession
+    ExecutionSession,
+    createExecutionSession,
+    disposeExecutionSession,
+    withExecutionSession,
+    -- * JITDylib
+    JITDylib(..),
+    createJITDylib,
+    -- ** Symbol search generators
+    addDynamicLibrarySearchGeneratorForCurrentProcess,
+    addDynamicLibrarySearchGenerator,
+    -- ** Symbol definitions
+    defineAbsoluteSymbols,
+    -- ** Symbol lookups
+    lookupSymbol,
+    JITSymbol(..),
+    JITSymbolError(..),
+    JITSymbolFlags(..),
+    defaultJITSymbolFlags,
+    -- * Mangled symbols
+    mangleSymbol,
+    disposeMangledSymbol,
+    withMangledSymbol,
+    -- * ThreadSafeContext
+    ThreadSafeContext,
+    -- ** Lifetime management
+    withThreadSafeContext,
+    createThreadSafeContext,
+    disposeThreadSafeContext,
+    -- * ThreadSafeModule
+    ThreadSafeModule(..),
+    -- ** Lifetime management
+    withClonedThreadSafeModule,
+    cloneAsThreadSafeModule,
+    disposeThreadSafeModule,
+    -- * Object layers
+    ObjectLayer,
+    addObjectFile,
+    -- ** ObjectLinkingLayer
+    ObjectLinkingLayer,
+    createObjectLinkingLayer,
+    -- ** RTDyldObjectLinkingLayer
+    RTDyldObjectLinkingLayer,
+    createRTDyldObjectLinkingLayer,
+    -- * IR layers
+    IRLayer,
+    addModule,
+    -- ** IRCompileLayer
+    IRCompileLayer,
+    createIRCompileLayer,
+  ) where
+
+import LLVM.Internal.OrcJIT
diff --git a/src/LLVM/PassManager.hs b/src/LLVM/PassManager.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/PassManager.hs
@@ -0,0 +1,14 @@
+-- | A 'PassManager' holds collection of passes, to be run on 'Module's.
+-- Build one with 'withPassManager':
+-- 
+--  * using 'CuratedPassSetSpec' if you want optimization but not to play with your compiler
+--
+--  * using 'PassSetSpec' if you do want to play with your compiler
+module LLVM.PassManager (
+  PassManager,
+  PassSetSpec(..), defaultPassSetSpec, defaultCuratedPassSetSpec,
+  withPassManager,
+  runPassManager
+  ) where
+
+import LLVM.Internal.PassManager
diff --git a/src/LLVM/Prelude.hs b/src/LLVM/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Prelude.hs
@@ -0,0 +1,68 @@
+-- | This module is presents a prelude mostly like the post-Applicative-Monad world of
+-- base >= 4.8 / ghc >= 7.10, as well as the post-Semigroup-Monoid world of
+-- base >= 4.11 / ghc >= 8.4, even on earlier versions. It's intended as an internal library
+-- for llvm-hs-pure and llvm-hs; it's exposed only to be shared between the two.
+module LLVM.Prelude (
+    module Prelude,
+    module Data.Data,
+    module GHC.Generics,
+    module Data.Int,
+    module Data.Word,
+    module Data.Functor,
+    module Data.Foldable,
+    module Data.Semigroup,
+    module Data.Traversable,
+    module Control.Applicative,
+    module Control.Monad,
+    ByteString,
+    ShortByteString,
+    fromMaybe,
+    leftBiasedZip,
+    findM,
+    ifM
+    ) where
+
+import Prelude hiding (
+    mapM, mapM_,
+    sequence, sequence_,
+    concat,
+    foldr, foldr1, foldl, foldl1,
+    minimum, maximum, sum, product, all, any, and, or,
+    concatMap,
+    elem, notElem,
+  )
+import Data.Data (Data, Typeable)
+import GHC.Generics (Generic)
+import Data.Int
+import Data.Maybe (fromMaybe)
+import Data.Word
+import Data.Functor
+import Data.Foldable
+import Data.Semigroup (Semigroup((<>)))
+import Data.Traversable
+import Control.Applicative
+import Control.Monad hiding (
+    forM, forM_,
+    mapM, mapM_,
+    sequence, sequence_,
+    msum
+  )
+
+import Data.ByteString (ByteString)
+import Data.ByteString.Short (ShortByteString)
+
+leftBiasedZip :: [a] -> [b] -> [(a, Maybe b)]
+leftBiasedZip [] _ = []
+leftBiasedZip xs [] = map (, Nothing) xs
+leftBiasedZip (x:xs) (y:ys) = (x, Just y) : leftBiasedZip xs ys
+
+ifM :: Monad m => m Bool -> m a -> m a -> m a
+ifM cond ifTrue ifFalse = do
+  cond' <- cond
+  if cond'
+    then ifTrue
+    else ifFalse
+
+findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
+findM _ [] = return Nothing
+findM p (x:xs) = ifM (p x) (return $ Just x) (findM p xs)
diff --git a/src/LLVM/Relocation.hs b/src/LLVM/Relocation.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Relocation.hs
@@ -0,0 +1,12 @@
+-- | Relocations, used in specifying TargetMachine
+module LLVM.Relocation where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1Reloc.html>
+data Model 
+    = Default
+    | Static
+    | PIC
+    | DynamicNoPIC
+    deriving (Eq, Read, Show, Typeable, Data, Generic)
diff --git a/src/LLVM/Target.hs b/src/LLVM/Target.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Target.hs
@@ -0,0 +1,22 @@
+-- | A 'Target' describes that for which code may be intended. Targets are used both during actual
+-- | lowering of LLVM IR to machine code and by some optimization passes which use the target to
+-- | judge costs.
+module LLVM.Target (
+   lookupTarget,
+   TargetOptions,
+   Target, TargetMachine, TargetLowering,
+   CPUFeature(..),
+   withTargetOptions, peekTargetOptions, pokeTargetOptions,
+   withTargetMachine, withHostTargetMachine, withHostTargetMachineDefault, targetMachineOptions,
+   getTargetLowering,
+   getTargetMachineTriple, getDefaultTargetTriple, getProcessTargetTriple, getHostCPUName, getHostCPUFeatures,
+   getTargetMachineDataLayout, initializeNativeTarget, initializeAllTargets,
+   TargetLibraryInfo,
+   getLibraryFunction,
+   getLibraryFunctionName,
+   setLibraryFunctionAvailableWithName,
+   withTargetLibraryInfo
+ ) where
+
+import LLVM.Internal.Target
+
diff --git a/src/LLVM/Target/LibraryFunction.hs b/src/LLVM/Target/LibraryFunction.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Target/LibraryFunction.hs
@@ -0,0 +1,7 @@
+-- | A 'LibraryFunction' identifies a function of which LLVM has particular knowledge.
+module LLVM.Target.LibraryFunction (
+  LibraryFunction(..)
+ ) where
+
+
+import LLVM.Internal.LibraryFunction
diff --git a/src/LLVM/Target/Options.hs b/src/LLVM/Target/Options.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Target/Options.hs
@@ -0,0 +1,116 @@
+-- | <http://llvm.org/doxygen/classllvm_1_1TargetOptions.html>
+module LLVM.Target.Options where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1FloatABI.html#aea077c52d84934aabf9445cef9eab2e2>
+data FloatABI
+  = FloatABIDefault
+  | FloatABISoft
+  | FloatABIHard
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1FPOpFusion.html#a9c71bae9f02af273833fde586d529fc5>
+data FloatingPointOperationFusionMode
+  = FloatingPointOperationFusionFast
+  | FloatingPointOperationFusionStandard
+  | FloatingPointOperationFusionStrict
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <https://llvm.org/doxygen/namespacellvm.html#aa100a124c9d33561b0950011928aae00>
+data DebugCompressionType
+  = CompressNone -- ^ No compression
+  | CompressGNU -- ^ zlib-gnu style compression
+  | CompressZ -- ^ zlib style compression
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1ThreadModel.html#a299c775d35e28348ecfbe03c38c17fe1>
+data ThreadModel
+  = ThreadModelPOSIX
+  | ThreadModelSingle
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm.html#adc04b17f40513e658e600a26842b1ed6>
+data DebuggerKind
+  = DebuggerDefault
+  | DebuggerGDB
+  | DebuggerLLDB
+  | DebuggerSCE
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm.html#ada924e855250645672a493841803ff91>
+data EABIVersion
+  = EABIVersionUnknown
+  | EABIVersionDefault
+  | EABIVersion4
+  | EABIVersion5
+  | EABIVersionGNU
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm_1_1FPDenormal.html#aa0e896c04e0537cf6d0926f3c8db6d6c>
+data FloatingPointDenormalMode
+  = FloatingPointDenormalIEEE -- ^ IEEE 754 denormal numbers
+  | FloatingPointDenormalPreserveSign -- ^ The sign of a flushed-to-zero number is preserved in the sign of 0
+  | FloatingPointDenormalPositiveZero -- ^ Denormals are flushed to positive zero
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | <http://llvm.org/doxygen/namespacellvm.html#a2ca3855108426698ff21517a7c884c84>
+data ExceptionHandling
+  = ExceptionHandlingNone -- ^ No exception support
+  | ExceptionHandlingDwarfCFI -- ^ DWARF-like instruction based exceptions
+  | ExceptionHandlingSjLj -- ^ setjmp/longjmp based exceptions
+  | ExceptionHandlingARM -- ^ ARM EHABI
+  | ExceptionHandlingWinEH -- ^ Windows Exception Handling
+  deriving (Eq, Ord, Read, Show, Enum, Bounded, Typeable, Data, Generic)
+
+-- | The options of a 'LLVM.Target.TargetOptions'
+-- <http://llvm.org/doxygen/classllvm_1_1TargetOptions.html>
+data Options = Options {
+  unsafeFloatingPointMath :: Bool,
+  noInfinitiesFloatingPointMath :: Bool,
+  noNaNsFloatingPointMath :: Bool,
+  noTrappingFloatingPointMath :: Bool,
+  noSignedZeroesFloatingPointMath :: Bool,
+  honorSignDependentRoundingFloatingPointMathOption :: Bool,
+  noZerosInBSS :: Bool,
+  guaranteedTailCallOptimization :: Bool,
+  stackSymbolOrdering :: Bool,
+  enableFastInstructionSelection :: Bool,
+  useInitArray :: Bool,
+  disableIntegratedAssembler :: Bool,
+  compressDebugSections :: DebugCompressionType,
+  relaxELFRelocations :: Bool,
+  functionSections :: Bool,
+  dataSections :: Bool,
+  uniqueSectionNames :: Bool,
+  trapUnreachable :: Bool,
+  emulatedThreadLocalStorage :: Bool,
+  enableInterProceduralRegisterAllocation :: Bool,
+  stackAlignmentOverride :: Word32,
+  floatABIType :: FloatABI,
+  allowFloatingPointOperationFusion :: FloatingPointOperationFusionMode,
+  threadModel :: ThreadModel,
+  eabiVersion :: EABIVersion,
+  debuggerTuning :: DebuggerKind,
+  floatingPointDenormalMode :: FloatingPointDenormalMode,
+  exceptionModel :: ExceptionHandling,
+  machineCodeOptions :: MachineCodeOptions
+  }
+  deriving (Eq, Ord, Read, Show)
+
+-- | <http://llvm.org/doxygen/classllvm_1_1MCTargetOptions.html>
+data MachineCodeOptions = MachineCodeOptions {
+  relaxAll :: Bool,
+  noExecutableStack :: Bool,
+  fatalWarnings :: Bool,
+  noWarnings :: Bool,
+  noDeprecatedWarning :: Bool,
+  saveTemporaryLabels :: Bool,
+  useDwarfDirectory :: Bool,
+  incrementalLinkerCompatible :: Bool,
+  showMachineCodeEncoding :: Bool,
+  showMachineCodeInstructions :: Bool,
+  verboseAssembly :: Bool,
+  preserveComentsInAssembly :: Bool
+  }
+  deriving (Eq, Ord, Read, Show)
diff --git a/src/LLVM/Threading.hs b/src/LLVM/Threading.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Threading.hs
@@ -0,0 +1,24 @@
+-- | functionality necessary when running LLVM in multiple threads at the same time.
+module LLVM.Threading (
+  setMultithreaded,
+  isMultithreaded
+  ) where
+
+import LLVM.Prelude
+
+import LLVM.Internal.Threading
+
+{-# DEPRECATED setMultithreaded "LLVM no longer features runtime control of multithreading support" #-}
+-- | This function used set the multithreading mode of LLVM, but that feature no longer exists. Threading is
+-- controlled only at runtime with the configure flag --enable-threads (default is YES). This function will
+-- now check that the the compiled-in multithreading support (returned by 'isMultithreaded') is
+-- sufficient to support the requested access, and fail if not, so as to prevent uncontrolled use of a
+-- version of LLVM compiled to be capable only of singled threaded use by haskell code requesting
+-- multithreading support.
+setMultithreaded :: Bool -> IO ()
+setMultithreaded desired = do
+  actual <- isMultithreaded
+  when (desired && not actual) $
+     fail $ "Multithreading support requested but not available. " ++ 
+            "Please use an LLVM built with threading enabled"
+  return ()
diff --git a/src/LLVM/Transforms.hs b/src/LLVM/Transforms.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Transforms.hs
@@ -0,0 +1,149 @@
+{-# LANGUAGE OverloadedStrings #-}
+-- | This module provides an enumeration of the various transformation (e.g. optimization) passes
+-- provided by LLVM. They can be used to create a 'LLVM.PassManager.PassManager' to, in turn,
+-- run the passes on 'LLVM.Module.Module's. If you don't know what passes you want, consider
+-- instead using 'LLVM.PassManager.CuratedPassSetSpec'.
+module LLVM.Transforms where
+
+import LLVM.Prelude
+
+-- | <http://llvm.org/docs/Passes.html#transform-passes>
+-- A few passes can make use of information in a 'LLVM.Target.TargetMachine' if one
+-- is provided to 'LLVM.PassManager.createPassManager'.
+-- <http://llvm.org/doxygen/classllvm_1_1Pass.html>
+data Pass
+  -- here begin the Scalar passes
+  = AggressiveDeadCodeElimination
+  | BreakCriticalEdges
+  -- | can use a 'LLVM.Target.TargetMachine'
+  | CodeGenPrepare
+  | CorrelatedValuePropagation
+  | DeadCodeElimination
+  | DeadStoreElimination
+  | DemoteRegisterToMemory
+  | EarlyCommonSubexpressionElimination
+  | GlobalValueNumbering { noLoads :: Bool }
+  | InductionVariableSimplify
+  | InstructionCombining
+  -- | Instruction simplification includes constant folding
+  | InstructionSimplify
+  | JumpThreading
+  | LoopClosedSingleStaticAssignment
+  | LoopInvariantCodeMotion
+  | LoopDeletion
+  | LoopIdiom
+  | LoopInstructionSimplify
+  | LoopRotate
+  | LoopStrengthReduce
+  | LoopUnroll { loopUnrollThreshold :: Maybe Word, count :: Maybe Word, allowPartial :: Maybe Bool }
+  | LoopUnswitch { optimizeForSize :: Bool }
+  | LowerAtomic
+  | LowerInvoke
+  | LowerSwitch
+  | LowerExpectIntrinsic
+  | MemcpyOptimization
+  | PromoteMemoryToRegister
+  | Reassociate
+  | ScalarReplacementOfAggregates { requiresDominatorTree :: Bool }
+  | OldScalarReplacementOfAggregates {
+      oldScalarReplacementOfAggregatesThreshold :: Maybe Word,
+      useDominatorTree :: Bool,
+      structMemberThreshold :: Maybe Word,
+      arrayElementThreshold :: Maybe Word,
+      scalarLoadThreshold :: Maybe Word
+    }
+  | SparseConditionalConstantPropagation
+  | SimplifyLibCalls
+  | SimplifyControlFlowGraph
+  | Sinking
+  | TailCallElimination
+
+  -- here begin the Interprocedural passes
+  | AlwaysInline { insertLifetime :: Bool }
+  | ArgumentPromotion
+  | ConstantMerge
+  | FunctionAttributes
+  | FunctionInlining {
+      functionInliningThreshold :: Word
+    }
+  | GlobalDeadCodeElimination
+  | InternalizeFunctions { exportList :: [String] }
+  | InterproceduralSparseConditionalConstantPropagation
+  | MergeFunctions
+  | PartialInlining
+  | PruneExceptionHandling
+  | StripDeadDebugInfo
+  | StripDebugDeclare
+  | StripNonDebugSymbols
+  | StripSymbols { onlyDebugInfo :: Bool }
+
+  -- here begin the vectorization passes
+  | LoopVectorize {
+      interleaveOnlyWhenForced :: Bool,
+      vectorizeOnlyWhenForced :: Bool
+    }
+  | SuperwordLevelParallelismVectorize
+
+  -- here begin the instrumentation passes
+  | GCOVProfiler {
+      emitNotes :: Bool,
+      emitData :: Bool,
+      version :: GCOVVersion,
+      noRedZone :: Bool,
+      atomic :: Bool,
+      filter :: String,
+      exclude :: String
+    }
+  | AddressSanitizer
+  | AddressSanitizerModule
+  | MemorySanitizer {
+      trackOrigins :: Bool,
+      recover :: Bool,
+      kernel :: Bool
+    }
+  | ThreadSanitizer
+  | BoundsChecking
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Defaults for the 'LoopVectorize' pass
+defaultLoopVectorize :: Pass
+defaultLoopVectorize = LoopVectorize {
+    interleaveOnlyWhenForced = False,
+    vectorizeOnlyWhenForced = False
+  }
+
+-- | See <http://gcc.gnu.org/viewcvs/gcc/trunk/gcc/gcov-io.h?view=markup>.
+newtype GCOVVersion = GCOVVersion ShortByteString
+  deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
+
+-- | Defaults for 'GCOVProfiler'.
+defaultGCOVProfiler :: Pass
+defaultGCOVProfiler = GCOVProfiler {
+    emitNotes = True,
+    emitData = True,
+    version = GCOVVersion "402*",
+    noRedZone = False,
+    atomic = True,
+    LLVM.Transforms.filter = "",
+    exclude = ""
+  }
+
+-- | Defaults for 'AddressSanitizer'.
+defaultAddressSanitizer :: Pass
+defaultAddressSanitizer = AddressSanitizer
+
+-- | Defaults for 'AddressSanitizerModule'.
+defaultAddressSanitizerModule :: Pass
+defaultAddressSanitizerModule = AddressSanitizerModule
+
+-- | Defaults for 'MemorySanitizer'.
+defaultMemorySanitizer :: Pass
+defaultMemorySanitizer = MemorySanitizer {
+  trackOrigins = False,
+  recover = False,
+  kernel = False
+}
+
+-- | Defaults for 'ThreadSanitizer'.
+defaultThreadSanitizer :: Pass
+defaultThreadSanitizer = ThreadSanitizer
diff --git a/src/LLVM/Triple.hs b/src/LLVM/Triple.hs
new file mode 100644
--- /dev/null
+++ b/src/LLVM/Triple.hs
@@ -0,0 +1,380 @@
+{-# LANGUAGE RecordWildCards #-}
+
+-- | A 'Triple' represents a target triple, which is a target host description.
+-- | Target triples consistent of a few components: architecture, vendor,
+-- | operating system, and environment.
+-- | <https://llvm.org/docs/LangRef.html#target-triple>
+
+module LLVM.Triple (
+   Triple (..), Architecture (..), Vendor (..), OS (..), unknownTriple, parseTriple, tripleToString
+ ) where
+
+import LLVM.Prelude
+import Control.Monad.Trans.Except
+import Data.Attoparsec.ByteString
+import Data.Attoparsec.ByteString.Char8
+import Data.ByteString.Char8 as ByteString hiding (map, foldr)
+import Data.ByteString.Short hiding (pack, foldr)
+
+import Data.Map (Map, (!))
+import qualified Data.Map as Map
+
+data Architecture
+  = UnknownArch
+  | Arm            -- ARM (little endian): arm armv.* xscale
+  | Armeb          -- ARM (big endian): armeb
+  | Aarch64        -- AArch64 (little endian): aarch64
+  | Aarch64_be     -- AArch64 (big endian): aarch64_be
+  | Aarch64_32     -- AArch64 (little endian) ILP32: aarch64_32
+  | Arc            -- ARC: Synopsys ARC
+  | Avr            -- AVR: Atmel AVR microcontroller
+  | Bpfel          -- eBPF or extended BPF or 64-bit BPF (little endian)
+  | Bpfeb          -- eBPF or extended BPF or 64-bit BPF (big endian)
+  | Csky           -- CSKY: csky
+  | Hexagon        -- Hexagon: hexagon
+  | Mips           -- MIPS: mips mipsallegrex mipsr6
+  | Mipsel         -- MIPSEL: mipsel mipsallegrexe mipsr6el
+  | Mips64         -- MIPS64: mips64 mips64r6 mipsn32 mipsn32r6
+  | Mips64el       -- MIPS64EL: mips64el mips64r6el mipsn32el mipsn32r6el
+  | Msp430         -- MSP430: msp430
+  | Ppc            -- PPC: powerpc
+  | Ppcle          -- PPCLE: powerpc (little endian)
+  | Ppc64          -- PPC64: powerpc64 ppu
+  | Ppc64le        -- PPC64LE: powerpc64le
+  | R600           -- R600: AMD GPUs HD2XXX - HD6XXX
+  | Amdgcn         -- AMDGCN: AMD GCN GPUs
+  | Riscv32        -- RISC-V (32-bit): riscv32
+  | Riscv64        -- RISC-V (64-bit): riscv64
+  | Sparc          -- Sparc: sparc
+  | Sparcv9        -- Sparcv9: Sparcv9
+  | Sparcel        -- Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
+  | Systemz        -- SystemZ: s390x
+  | Tce            -- TCE (http://tce.cs.tut.fi/): tce
+  | Tcele          -- TCE little endian (http://tce.cs.tut.fi/): tcele
+  | Thumb          -- Thumb (little endian): thumb thumbv.*
+  | Thumbeb        -- Thumb (big endian): thumbeb
+  | X86            -- X86: i[3-9]86
+  | X86_64         -- X86-64: amd64 x86_64
+  | Xcore          -- XCore: xcore
+  | Nvptx          -- NVPTX: 32-bit
+  | Nvptx64        -- NVPTX: 64-bit
+  | Le32           -- le32: generic little-endian 32-bit CPU (PNaCl)
+  | Le64           -- le64: generic little-endian 64-bit CPU (PNaCl)
+  | Amdil          -- AMDIL
+  | Amdil64        -- AMDIL with 64-bit pointers
+  | Hsail          -- AMD HSAIL
+  | Hsail64        -- AMD HSAIL with 64-bit pointers
+  | Spir           -- SPIR: standard portable IR for OpenCL 32-bit version
+  | Spir64         -- SPIR: standard portable IR for OpenCL 64-bit version
+  | Kalimba        -- Kalimba: generic kalimba
+  | Shave          -- SHAVE: Movidius vector VLIW processors
+  | Lanai          -- Lanai: Lanai 32-bit
+  | Wasm32         -- WebAssembly with 32-bit pointers
+  | Wasm64         -- WebAssembly with 64-bit pointers
+  | Renderscript32 -- 32-bit RenderScript
+  | Renderscript64 -- 64-bit RenderScript
+  | Ve             -- NEC SX-Aurora Vector Engine
+  deriving (Eq, Ord, Show)
+
+-- NOTE: SubArchitecture is not currently used.
+data SubArchitecture
+  = NoSubArch
+  | ARMSubArch_v8_7a
+  | ARMSubArch_v8_6a
+  | ARMSubArch_v8_5a
+  | ARMSubArch_v8_4a
+  | ARMSubArch_v8_3a
+  | ARMSubArch_v8_2a
+  | ARMSubArch_v8_1a
+  | ARMSubArch_v8
+  | ARMSubArch_v8r
+  | ARMSubArch_v8m_baseline
+  | ARMSubArch_v8m_mainline
+  | ARMSubArch_v8_1m_mainline
+  | ARMSubArch_v7
+  | ARMSubArch_v7em
+  | ARMSubArch_v7m
+  | ARMSubArch_v7s
+  | ARMSubArch_v7k
+  | ARMSubArch_v7ve
+  | ARMSubArch_v6
+  | ARMSubArch_v6m
+  | ARMSubArch_v6k
+  | ARMSubArch_v6t2
+  | ARMSubArch_v5
+  | ARMSubArch_v5te
+  | ARMSubArch_v4t
+  | AArch64SubArch_arm64e
+  | KalimbaSubArch_v3
+  | KalimbaSubArch_v4
+  | KalimbaSubArch_v5
+  | MipsSubArch_r6
+  | PPCSubArch_spe
+  deriving (Eq, Ord, Show)
+
+data Vendor
+  = UnknownVendor
+  | Apple
+  | PC
+  | SCEI
+  | Freescale
+  | IBM
+  | ImaginationTechnologies
+  | MipsTechnologies
+  | NVIDIA
+  | CSR
+  | Myriad
+  | AMD
+  | Mesa
+  | SUSE
+  | OpenEmbedded
+  deriving (Eq, Ord, Show)
+
+data OS
+  = UnknownOS
+  | Ananas
+  | CloudABI
+  | Darwin
+  | DragonFly
+  | FreeBSD
+  | Fuchsia
+  | IOS
+  | KFreeBSD
+  | Linux
+  | Lv2        -- PS3
+  | MacOSX
+  | NetBSD
+  | OpenBSD
+  | Solaris
+  | Win32
+  | ZOS
+  | Haiku
+  | Minix
+  | RTEMS
+  | NaCl       -- Native Client
+  | AIX
+  | CUDA       -- NVIDIA CUDA
+  | NVCL       -- NVIDIA OpenCL
+  | AMDHSA     -- AMD HSA Runtime
+  | PS4
+  | ELFIAMCU
+  | TvOS       -- Apple tvOS
+  | WatchOS    -- Apple watchOS
+  | Mesa3D
+  | Contiki
+  | AMDPAL     -- AMD PAL Runtime
+  | HermitCore -- HermitCore Unikernel/Multikernel
+  | Hurd       -- GNU/Hurd
+  | WASI       -- Experimental WebAssembly OS
+  | Emscripten
+  deriving (Eq, Ord, Show)
+
+data Environment
+  = UnknownEnvironment
+  | GNU
+  | GNUABIN32
+  | GNUABI64
+  | GNUEABI
+  | GNUEABIHF
+  | GNUX32
+  | GNUILP32
+  | CODE16
+  | EABI
+  | EABIHF
+  | Android
+  | Musl
+  | MuslEABI
+  | MuslEABIHF
+  | MSVC
+  | Itanium
+  | Cygnus
+  | CoreCLR
+  | Simulator -- Simulator variants of other systems e.g. Apple's iOS
+  | MacABI -- Mac Catalyst variant of Apple's iOS deployment target.
+  deriving (Eq, Ord, Show)
+
+data ObjectFormat
+  = UnknownObjectFormat
+  | COFF
+  | ELF
+  | GOFF
+  | MachO
+  | Wasm
+  | XCOFF
+  deriving (Eq, Ord, Show)
+
+data Triple = Triple {
+    architecture :: Architecture,
+    subarchitecture :: SubArchitecture,
+    os :: OS,
+    vendor :: Vendor,
+    environment :: Environment,
+    objectFormat :: ObjectFormat
+  } deriving (Eq, Ord, Show)
+
+unknownTriple :: Triple
+unknownTriple = Triple {
+    architecture = UnknownArch,
+    subarchitecture = NoSubArch,
+    vendor = UnknownVendor,
+    os = UnknownOS,
+    environment = UnknownEnvironment,
+    objectFormat = UnknownObjectFormat
+  }
+
+invertBijection :: (Ord k, Ord v) => Map k v -> Map v k
+invertBijection = Map.foldrWithKey (flip Map.insert) Map.empty
+
+architectureFromStringMap :: Map String Architecture
+architectureFromStringMap = Map.fromList [
+  ("unknown", UnknownArch),
+  ("arm", Arm),
+  ("armeb", Armeb),
+  ("aarch64", Aarch64),
+  ("aarch64_be", Aarch64_be),
+  ("aarch64_32", Aarch64_32),
+  ("arc", Arc),
+  ("avr", Avr),
+  ("bpfel", Bpfel),
+  ("bpfeb", Bpfeb),
+  ("csky", Csky),
+  ("hexagon", Hexagon),
+  ("mips", Mips),
+  ("mipsel", Mipsel),
+  ("mips64", Mips64),
+  ("mips64el", Mips64el),
+  ("msp430", Msp430),
+  ("ppc", Ppc),
+  ("ppcle", Ppcle),
+  ("ppc64", Ppc64),
+  ("ppc64le", Ppc64le),
+  ("r600", R600),
+  ("amdgcn", Amdgcn),
+  ("riscv32", Riscv32),
+  ("riscv64", Riscv64),
+  ("sparc", Sparc),
+  ("sparcv9", Sparcv9),
+  ("sparcel", Sparcel),
+  ("systemz", Systemz),
+  ("tce", Tce),
+  ("tcele", Tcele),
+  ("thumb", Thumb),
+  ("thumbeb", Thumbeb),
+  ("x86", X86),
+  ("x86_64", X86_64),
+  ("xcore", Xcore),
+  ("nvptx", Nvptx),
+  ("nvptx64", Nvptx64),
+  ("le32", Le32),
+  ("le64", Le64),
+  ("amdil", Amdil),
+  ("amdil64", Amdil64),
+  ("hsail", Hsail),
+  ("hsail64", Hsail64),
+  ("spir", Spir),
+  ("spir64", Spir64),
+  ("kalimba", Kalimba),
+  ("shave", Shave),
+  ("lanai", Lanai),
+  ("wasm32", Wasm32),
+  ("wasm64", Wasm64),
+  ("renderscript32", Renderscript32),
+  ("renderscript64", Renderscript64),
+  ("ve", Ve)
+  ]
+
+architectureToStringMap :: Map Architecture String
+architectureToStringMap = invertBijection architectureFromStringMap
+
+vendorFromStringMap :: Map String Vendor
+vendorFromStringMap = Map.fromList [
+  ("apple"                  , Apple                  ),
+  ("pc"                     , PC                     ),
+  ("scei"                   , SCEI                   ),
+  ("freescale"              , Freescale              ),
+  ("ibm"                    , IBM                    ),
+  ("imaginationtechnologies", ImaginationTechnologies),
+  ("mipstechnologies"       , MipsTechnologies       ),
+  ("nvidia"                 , NVIDIA                 ),
+  ("csr"                    , CSR                    ),
+  ("myriad"                 , Myriad                 ),
+  ("amd"                    , AMD                    ),
+  ("mesa"                   , Mesa                   ),
+  ("suse"                   , SUSE                   ),
+  ("openembedded"           , OpenEmbedded           )
+  ]
+
+vendorToStringMap :: Map Vendor String
+vendorToStringMap = invertBijection vendorFromStringMap
+
+osFromStringMap :: Map String OS
+osFromStringMap = Map.fromList [
+  ("ananas"    , Ananas    ),
+  ("cloudabi"  , CloudABI  ),
+  ("darwin"    , Darwin    ),
+  ("dragonfly" , DragonFly ),
+  ("freebsd"   , FreeBSD   ),
+  ("fuchsia"   , Fuchsia   ),
+  ("ios"       , IOS       ),
+  ("kfreebsd"  , KFreeBSD  ),
+  ("linux"     , Linux     ),
+  ("lv2"       , Lv2       ),
+  ("macosx"    , MacOSX    ),
+  ("netbsd"    , NetBSD    ),
+  ("openbsd"   , OpenBSD   ),
+  ("solaris"   , Solaris   ),
+  ("win32"     , Win32     ),
+  ("zos"       , ZOS       ),
+  ("haiku"     , Haiku     ),
+  ("minix"     , Minix     ),
+  ("rtems"     , RTEMS     ),
+  ("nacl"      , NaCl      ),
+  ("aix"       , AIX       ),
+  ("cuda"      , CUDA      ),
+  ("nvcl"      , NVCL      ),
+  ("amdhsa"    , AMDHSA    ),
+  ("ps4"       , PS4       ),
+  ("elfiamcu"  , ELFIAMCU  ),
+  ("tvos"      , TvOS      ),
+  ("watchos"   , WatchOS   ),
+  ("mesa3d"    , Mesa3D    ),
+  ("contiki"   , Contiki   ),
+  ("amdpal"    , AMDPAL    ),
+  ("hermitcore", HermitCore),
+  ("hurd"      , Hurd      ),
+  ("wasi"      , WASI      ),
+  ("emscripten", Emscripten)
+  ]
+
+osToStringMap :: Map OS String
+osToStringMap = invertBijection osFromStringMap
+
+tripleToString :: Triple -> ShortByteString
+tripleToString Triple {..} =
+  toShort $ ByteString.intercalate (pack "-") [
+    pack (architectureToStringMap ! architecture),
+    pack (vendorToStringMap ! vendor),
+    pack (osToStringMap ! os)
+  ]
+
+parseTriple :: ShortByteString -> Except String Triple
+parseTriple triple = do
+  let
+    tripleStr = fromShort triple
+    parseSpec :: Parser (Triple -> Triple)
+    parseSpec = choice [
+      do
+        arch <- choice [string (pack s) $> a | (s, a) <- Map.toList architectureFromStringMap]
+        pure $ \t -> t { architecture = arch },
+      do
+        vendor <- choice [string (pack s) $> v | (s, v) <- Map.toList vendorFromStringMap]
+        pure $ \t -> t { vendor = vendor },
+      do
+        os <- choice [string (pack s) $> o | (s, o) <- Map.toList osFromStringMap]
+        pure $ \t -> t { os = os }
+     ]
+   in
+    case parseOnly (parseSpec `sepBy` char '-') tripleStr of
+      Left _ -> throwE $ "ill-formed triple: " ++ show tripleStr
+      Right fs -> pure $ foldr ($) unknownTriple fs
+
diff --git a/test/LLVM/Test/Analysis.hs b/test/LLVM/Test/Analysis.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Analysis.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Analysis where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad.Trans.Except
+
+import LLVM.Module
+import LLVM.Context
+import LLVM.Analysis
+
+import LLVM.AST as A
+import LLVM.AST.Type as A.T
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import LLVM.AST.DataLayout
+import qualified LLVM.AST.IntegerPredicate as IPred
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+
+import qualified LLVM.Relocation as R
+import qualified LLVM.CodeModel as CM
+import qualified LLVM.CodeGenOpt as CGO
+
+tests = testGroup "Analysis" [
+  testGroup "Verifier" [
+{-
+    -- this test will cause an assertion if LLVM is compiled with assertions on.
+    testCase "Module" $ do
+      let ast = Module "<string>" Nothing Nothing [
+            GlobalDefinition $ Function L.External V.Default CC.C [] A.T.void (Name "foo") ([
+                Parameter i32 (Name "x") []
+               ],False)
+             [] 
+             Nothing 0 Nothing         
+             [
+              BasicBlock (UnName 0) [
+                UnName 1 := Call {
+                  isTailCall = False,
+                  callingConvention = CC.C,
+                  returnAttributes = [],
+                  function = Right (ConstantOperand (C.GlobalReference (A.T.FunctionType A.T.void [A.T.i32] False) (Name "foo"))),
+                  arguments = [
+                   (ConstantOperand (C.Int 8 1), [])
+                  ],
+                  functionAttributes = [],
+                  metadata = []
+                 }
+              ] (
+                Do $ Ret Nothing []
+              )
+             ]
+            ]
+      Left s <- withContext $ \context -> withModuleFromAST context ast $ runExceptT . verify
+      s @?= "Call parameter type does not match function signature!\n\
+            \i8 1\n\
+            \ i32  call void @foo(i8 1)\n\
+            \Broken module found, compilation terminated.\n\
+            \Broken module found, compilation terminated.\n",
+-}
+
+    testGroup "regression" [
+      testCase "load synchronization" $ do
+       let str = "; ModuleID = '<string>'\n\
+                 \source_filename = \"<string>\"\n\
+                 \\n\
+                 \define double @my_function2(double* %input_0) {\n\
+                 \foo:\n\
+                 \  %tmp_input_w0 = getelementptr inbounds double, double* %input_0, i64 0\n\
+                 \  %0 = load double, double* %tmp_input_w0, align 8\n\
+                 \  ret double %0\n\
+                 \}\n"
+           ast = 
+             Module "<string>" "<string>" Nothing Nothing [
+               GlobalDefinition $ functionDefaults {
+                 G.returnType = double,
+                 G.name = Name "my_function2",
+                 G.parameters = ([
+                   Parameter (ptr double) (Name "input_0") []
+                  ],False),
+                 G.basicBlocks = [
+                   BasicBlock (Name "foo") [ 
+                    Name "tmp_input_w0" := GetElementPtr {
+                      inBounds = True,
+                      address = LocalReference (ptr double) (Name "input_0"),
+                      indices = [ConstantOperand (C.Int 64 0)],
+                      metadata = []
+                    },
+                    UnName 0 := Load {
+                      volatile = False,
+                      address = LocalReference (ptr double) (Name "tmp_input_w0"),
+                      maybeAtomicity = Nothing,
+                      alignment = 8,
+                      metadata = []
+                    }
+                   ] (
+                     Do $ Ret (Just (LocalReference double (UnName 0))) []
+                   )
+                  ]
+                }
+              ]
+       strCheck ast str
+       withContext $ \context -> withModuleFromAST context ast verify
+     ]
+   ]
+ ]
diff --git a/test/LLVM/Test/Attribute.hs b/test/LLVM/Test/Attribute.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Attribute.hs
@@ -0,0 +1,143 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Attribute
+  ( tests
+  ) where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM
+import LLVM.AST hiding (DIFlag(..))
+import LLVM.AST.CallingConvention (CallingConvention(C))
+import LLVM.AST.Constant (Constant (Int, GlobalReference))
+import LLVM.AST.FunctionAttribute
+import LLVM.AST.Global (basicBlocks, name, returnType)
+import LLVM.AST.Type (i32, ptr)
+import LLVM.Context
+
+import Data.List
+import Prelude
+
+moduleAst :: LLVM.AST.Module
+moduleAst =
+  defaultModule
+  { moduleDefinitions =
+      [ GlobalDefinition
+          (functionDefaults
+           { returnType = i32
+           , name = "f"
+           , basicBlocks =
+               [ BasicBlock
+                   (UnName 0)
+                   []
+                   (Do
+                      (Ret
+                       { returnOperand = Just (ConstantOperand (Int 32 42))
+                       , metadata' = []
+                       }))
+               ]
+           })
+      , GlobalDefinition
+          (functionDefaults
+           { returnType = i32
+           , name = "call_15"
+           , basicBlocks =
+               [ BasicBlock
+                   (UnName 0)
+                   [ "result" :=
+                     Call
+                     { tailCallKind = Nothing
+                     , callingConvention = C
+                     , returnAttributes = []
+                     , function =
+                         Right
+                           (ConstantOperand
+                              (GlobalReference
+                                 (ptr
+                                    (FunctionType
+                                     { resultType = i32
+                                     , argumentTypes = []
+                                     , isVarArg = False
+                                     }))
+                                 ("f")))
+                     , arguments = []
+                     , functionAttributes = [Left (GroupID 0)]
+                     , metadata = []
+                     }
+                   ]
+                   (Do
+                      (Ret
+                       { returnOperand = Just (LocalReference i32 ("result"))
+                       , metadata' = []
+                       }))
+               ]
+           })
+      , FunctionAttributes
+          (GroupID 0)
+          [ AlwaysInline
+          , ArgMemOnly
+          , Builtin
+          , Cold
+          , Convergent
+          , InaccessibleMemOnly
+          , InaccessibleMemOrArgMemOnly
+          , InlineHint
+          , JumpTable
+          , MinimizeSize
+          , Naked
+          , NoBuiltin
+          , NoDuplicate
+          , NoImplicitFloat
+          , NoInline
+          , NoRecurse
+          , NoRedZone
+          , NoReturn
+          , NoUnwind
+          , NonLazyBind
+          , OptimizeForSize
+          , OptimizeNone
+          , ReadNone
+          , ReadOnly
+          , ReturnsTwice
+          , SafeStack
+          , SanitizeAddress
+          , SanitizeMemory
+          , SanitizeThread
+          , StackProtect
+          , StackProtectReq
+          , StackProtectStrong
+          , UWTable
+          , WriteOnly
+          , AllocSize 8 (Just 16)
+          , StackAlignment 8
+          , StringAttribute "bar" "baz"
+          , StringAttribute "foo" ""
+          , StringAttribute "qux" ""
+          ]
+      ]
+  }
+
+moduleStr :: String
+moduleStr =
+  unlines
+    [ "define i32 @f() {"
+    , "    ret i32 42"
+    , "}"
+    , ""
+    , "define i32 @call_15() {"
+    , "    %result = call i32 @f() \"foo\" \"bar\"=\"baz\" #0 alignstack(8) allocsize(8) allocsize(8, 16) alwaysinline argmemonly builtin cold convergent inaccessiblemem_or_argmemonly inaccessiblememonly inlinehint jumptable minsize naked nobuiltin noduplicate noimplicitfloat noinline nonlazybind norecurse noredzone noreturn nounwind optnone optsize readnone readonly returns_twice safestack sanitize_address sanitize_memory sanitize_thread ssp sspreq sspstrong uwtable writeonly"
+    , "    ret i32 %result"
+    , "}"
+    , ""
+    , "attributes #0 = { \"qux\" }"
+    ]
+
+tests :: TestTree
+tests =
+  testGroup "Attributes"
+    [ testCase "decoding of call attributes"  $ do
+        withContext $ \ctx -> do
+          withModuleFromLLVMAssembly ctx moduleStr $ \m -> do
+            ast <- moduleAST m
+            ast @?= moduleAst
+    ]
diff --git a/test/LLVM/Test/CallingConvention.hs b/test/LLVM/Test/CallingConvention.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/CallingConvention.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.CallingConvention where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Data.Maybe
+import Data.Monoid
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.AST
+import LLVM.AST.Type as T
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Global as G
+
+import qualified Data.ByteString.Char8 as ByteString
+
+tests = testGroup "CallingConvention" [
+  testCase name $ strCheck (defaultModule {
+    moduleDefinitions = [
+     GlobalDefinition $ functionDefaults {
+       G.returnType = i32,
+       G.name = Name "foo",
+       G.callingConvention = cc
+     }
+    ]
+   }) ("; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \declare" <> (if name == "" then "" else (" " <> ByteString.pack name)) <> " i32 @foo()\n")
+   | (name, cc) <- [
+   ("", CC.C),
+   ("fastcc", CC.Fast),
+   ("coldcc", CC.Cold),
+   ("ghccc", CC.GHC),
+   ("cc11", CC.HiPE),
+   ("webkit_jscc", CC.WebKit_JS),
+   ("anyregcc", CC.AnyReg),
+   ("preserve_mostcc", CC.PreserveMost),
+   ("preserve_allcc", CC.PreserveAll),
+   ("swiftcc", CC.Swift),
+   ("cxx_fast_tlscc", CC.CXX_FastTLS),
+   ("x86_stdcallcc", CC.X86_StdCall),
+   ("x86_fastcallcc", CC.X86_FastCall),
+   ("arm_apcscc", CC.ARM_APCS),
+   ("arm_aapcscc", CC.ARM_AAPCS),
+   ("arm_aapcs_vfpcc", CC.ARM_AAPCS_VFP),
+   ("msp430_intrcc", CC.MSP430_INTR),
+   ("x86_thiscallcc", CC.X86_ThisCall),
+   ("ptx_kernel", CC.PTX_Kernel),
+   ("ptx_device", CC.PTX_Device),
+   ("spir_func", CC.SPIR_FUNC),
+   ("spir_kernel", CC.SPIR_KERNEL),
+   ("intel_ocl_bicc", CC.Intel_OCL_BI),
+   ("x86_64_sysvcc", CC.X86_64_SysV),
+   ("win64cc", CC.Win64),
+   ("x86_vectorcallcc", CC.X86_VectorCall),
+   ("hhvmcc", CC.HHVM),
+   ("hhvm_ccc", CC.HHVM_C),
+   ("x86_intrcc", CC.X86_Intr),
+   ("avr_intrcc ", CC.AVR_Intr), -- The spaces are necessary because there is a typo in LLVM’s printer
+   ("avr_signalcc ", CC.AVR_Signal),
+   ("cc86", CC.AVR_Builtin),
+   ("amdgpu_vs", CC.AMDGPU_VS),
+   ("amdgpu_hs", CC.AMDGPU_HS),
+   ("amdgpu_gs", CC.AMDGPU_GS),
+   ("amdgpu_ps", CC.AMDGPU_PS),
+   ("amdgpu_cs", CC.AMDGPU_CS),
+   ("amdgpu_kernel", CC.AMDGPU_Kernel),
+   ("x86_regcallcc", CC.X86_RegCall),
+   ("cc94", CC.MSP430_Builtin)
+  ]
+ ]
diff --git a/test/LLVM/Test/Constants.hs b/test/LLVM/Test/Constants.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Constants.hs
@@ -0,0 +1,187 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Constants where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad
+import Data.Functor
+import Data.Maybe
+import Data.Monoid
+import Foreign.Ptr
+import Data.Word
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.Diagnostic
+import LLVM.AST
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.Float as F
+import qualified LLVM.AST.IntegerPredicate as IPred
+
+tests = testGroup "Constants" [
+  testCase name $ strCheck mAST mStr
+  | (name, type', value, str) <- [
+    (
+      "integer",
+      i32,
+      C.Int 32 1,
+      "global i32 1"
+    ), (
+      "wide integer",
+      IntegerType 65,
+      C.Int 65 1,
+      "global i65 1"
+    ), (
+      "big wide integer",
+      IntegerType 66,
+      C.Int 66 20000000000000000000,
+      "global i66 20000000000000000000"
+    ), (
+      "negative wide integer",
+      IntegerType 65,
+      C.Int 65 36893488147419103231,
+      "global i65 -1"
+    ), (
+      "half",
+      half,
+      C.Float (F.Half 0x1234),
+      "global half 0xH1234"
+    ), (
+      "float",
+      float,
+      C.Float (F.Single 1),
+      "global float 1.000000e+00"
+    ), (
+      "double",
+      double,
+      C.Float (F.Double 1),
+      "global double 1.000000e+00"
+    ), (
+      "quad",
+      fp128,
+      C.Float (F.Quadruple 0x0007000600050004 0x0003000200010000),
+      "global fp128 0xL00030002000100000007000600050004" -- yes, this order is weird
+    ), (
+      "quad 1.0",
+      fp128,
+      C.Float (F.Quadruple 0x3fff000000000000 0x0000000000000000),
+      "global fp128 0xL00000000000000003FFF000000000000" -- yes, this order is weird
+    ), (
+      "x86_fp80",
+      x86_fp80,
+      C.Float (F.X86_FP80 0x0004 0x8003000200010000),
+      "global x86_fp80 0xK00048003000200010000"
+{- don't know how to test this - LLVM's handling of this weird type is even weirder
+    ), (
+      "ppc_fp128",
+      ppc_fp128,
+      C.Float (F.PPC_FP128 0x0007000600050004 0x0003000200010000),
+      "global ppc_fp128 0xM????????????????"
+-}
+    ), (
+      "struct",
+      StructureType False (replicate 2 i32),
+      C.Struct Nothing False (replicate 2 (C.Int 32 1)),
+      "global { i32, i32 } { i32 1, i32 1 }"
+    ), (
+      "dataarray",
+      ArrayType 3 i32,
+      C.Array i32 [C.Int 32 i | i <- [1,2,1]],
+      "global [3 x i32] [i32 1, i32 2, i32 1]"
+    ), (
+      "array",
+      ArrayType 3 (StructureType False [i32]),
+      C.Array (StructureType False [i32]) [C.Struct Nothing False [C.Int 32 i] | i <- [1,2,1]],
+      "global [3 x { i32 }] [{ i32 } { i32 1 }, { i32 } { i32 2 }, { i32 } { i32 1 }]"
+    ), (
+      "datavector",
+      VectorType 3 i32,
+      C.Vector [C.Int 32 i | i <- [1,2,1]],
+      "global <3 x i32> <i32 1, i32 2, i32 1>"
+    ), (
+      "undef",
+      i32,
+      C.Undef i32,
+      "global i32 undef"
+    ), (
+      "binop/cast",
+      i64,
+      C.Add False False (C.PtrToInt (C.GlobalReference (ptr i32) (UnName 1)) i64) (C.Int 64 2),
+      "global i64 add (i64 ptrtoint (i32* @1 to i64), i64 2)"
+    ), (
+      "binop/cast nsw",
+      i64,
+      C.Add True False (C.PtrToInt (C.GlobalReference (ptr i32) (UnName 1)) i64) (C.Int 64 2),
+      "global i64 add nsw (i64 ptrtoint (i32* @1 to i64), i64 2)"
+    ), (
+      "icmp",
+      i1,
+      C.ICmp IPred.SGE (C.GlobalReference (ptr i32) (UnName 1)) (C.GlobalReference (ptr i32) (UnName 2)),
+      "global i1 icmp sge (i32* @1, i32* @2)"
+    ), (
+      "getelementptr",
+      ptr i32,
+      C.GetElementPtr True (C.GlobalReference (ptr i32) (UnName 1)) [C.Int 64 27],
+      "global i32* getelementptr inbounds (i32, i32* @1, i64 27)"
+    ), (
+      "selectvalue",
+      i32,
+      C.Select (C.PtrToInt (C.GlobalReference (ptr i32) (UnName 1)) i1)
+         (C.Int 32 1)
+         (C.Int 32 2),
+      "global i32 select (i1 ptrtoint (i32* @1 to i1), i32 1, i32 2)"
+    ), (
+      "extractelement",
+      i32,
+      C.ExtractElement
+         (C.BitCast
+             (C.PtrToInt (C.GlobalReference (ptr i32) (UnName 1)) i64)
+             (VectorType 2 i32))
+         (C.Int 32 1),
+      "global i32 extractelement (<2 x i32> bitcast (i64 ptrtoint (i32* @1 to i64) to <2 x i32>), i32 1)"
+    ), (
+     "addrspacecast",
+     (PointerType i32 (AddrSpace 1)),
+     C.AddrSpaceCast (C.GlobalReference (ptr i32) (UnName 1)) (PointerType i32 (AddrSpace 1)),
+     "global i32 addrspace(1)* addrspacecast (i32* @1 to i32 addrspace(1)*)"
+{-    ), (
+-- This test fails since LLVM 3.2!
+-- LLVM parses the extractValue instruction from a file via llvm-as properly, but it does not here.
+-- Rewritten by Andrew April 2021 to match the specific example in the LLVM language reference:
+-- https://llvm.org/docs/LangRef.html#extractvalue-instruction
+-- Bug filed with upstream here: https://bugs.llvm.org/show_bug.cgi?id=50092
+      "extractvalue",
+      i32,
+      C.ExtractValue
+        (C.Struct Nothing False [C.Int 32 0, C.Int 32 1])
+        [0],
+      "global i32 extractvalue ({i32, i32} {i32 0, i32 1}, 0)"
+-}
+    )
+   ],
+   let mAST = Module "<string>" "<string>" Nothing Nothing [
+             GlobalDefinition $ globalVariableDefaults {
+               G.name = UnName 0, G.type' = type', G.initializer = Just value
+             },
+             GlobalDefinition $ globalVariableDefaults {
+               G.name = UnName 1, G.type' = i32, G.initializer = Nothing
+             },
+             GlobalDefinition $ globalVariableDefaults {
+               G.name = UnName 2, G.type' = i32, G.initializer = Nothing
+             }
+           ]
+       mStr = "; ModuleID = '<string>'\nsource_filename = \"<string>\"\n\n@0 = " <> str <> "\n\
+              \@1 = external global i32\n\
+              \@2 = external global i32\n"
+ ]
diff --git a/test/LLVM/Test/DataLayout.hs b/test/LLVM/Test/DataLayout.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/DataLayout.hs
@@ -0,0 +1,105 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.DataLayout where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad.IO.Class
+import Data.Maybe
+import Data.Monoid
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.AST
+import LLVM.AST.DataLayout
+import LLVM.AST.AddrSpace
+import qualified LLVM.AST.Global as G
+import LLVM.Internal.Coding
+import LLVM.Internal.DataLayout
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.FFI.DataLayout (getTypeAllocSize)
+
+m s = "; ModuleID = '<string>'\nsource_filename = \"<string>\"\n" <> s
+t s = "target datalayout = \"" <> s <> "\"\n"
+ddl = defaultDataLayout BigEndian
+
+tests = testGroup "DataLayout" $
+  testCase "getTypeAllocSize" (withContext $ \ctx -> runEncodeAST ctx $ do
+    ty <- encodeM (IntegerType 8)
+    liftIO $ do
+      size <-
+        withFFIDataLayout
+          (ddl { typeLayouts = Map.singleton (IntegerAlign, 8) (AlignmentInfo 8 8) })
+          (\dl -> getTypeAllocSize dl ty)
+      size @?= 1
+      size <-
+        withFFIDataLayout
+          (ddl { typeLayouts = Map.singleton (IntegerAlign, 8) (AlignmentInfo 32 32) })
+          (\dl -> getTypeAllocSize dl ty)
+      size @?= 4)
+  :
+  [
+  testCase name $ strCheckC (Module "<string>" "<string>" mdl Nothing []) (m sdl) (m sdlc)
+  | (name, mdl, sdl, sdlc) <- [
+   ("none", Nothing, "", "")
+  ] ++ [
+   (name, Just mdl, t sdl, t (fromMaybe sdl msdlc))
+   | (name, mdl, sdl, msdlc) <- [
+    ("little-endian", defaultDataLayout LittleEndian, "e", Nothing),
+    ("big-endian", defaultDataLayout BigEndian, "E", Nothing),
+    ("native", ddl { nativeSizes = Just (Set.fromList [8,32]) }, "E-n8:32", Nothing),
+    (
+     "no pref",
+     ddl {
+       pointerLayouts = 
+         Map.singleton
+         (AddrSpace 0) 
+         (
+          8,
+          AlignmentInfo 64 64
+         )
+     },
+     "E-p:8:64",
+     Nothing
+    ), (
+     "no pref",
+     ddl {
+       pointerLayouts = 
+         Map.insert (AddrSpace 1) (8, AlignmentInfo 32 64) (pointerLayouts ddl)
+     },
+     "E-p1:8:32:64",
+     Nothing
+    ), (
+     "big",
+     ddl {
+       endianness = LittleEndian,
+       mangling = Just ELFMangling,
+       stackAlignment = Just 128,
+       pointerLayouts = Map.fromList [
+         (AddrSpace 0, (8, AlignmentInfo 8 16))
+        ],
+       typeLayouts = Map.fromList [
+         ((IntegerAlign, 1), AlignmentInfo 8 256),
+         ((IntegerAlign, 8), AlignmentInfo 8 256),
+         ((IntegerAlign, 16), AlignmentInfo 16 256),
+         ((IntegerAlign, 32), AlignmentInfo 32 256),
+         ((IntegerAlign, 64), AlignmentInfo 64 256),
+         ((VectorAlign, 64), AlignmentInfo 64 256),
+         ((VectorAlign, 128), AlignmentInfo 128 256),
+         ((FloatAlign, 32), AlignmentInfo 32 256),
+         ((FloatAlign, 64), AlignmentInfo 64 256),
+         ((FloatAlign, 80), AlignmentInfo 128 256)
+        ] `Map.union` typeLayouts ddl, 
+       aggregateLayout = AlignmentInfo 0 256,
+       nativeSizes = Just (Set.fromList [8,16,32,64])
+     },
+     "e-m:e-p:8:8:16-i1:8:256-i8:8:256-i16:16:256-i32:32:256-i64:64:256-v64:64:256-v128:128:256-f32:32:256-f64:64:256-f80:128:256-a:0:256-n8:16:32:64-S128",
+     Nothing
+    )
+   ]
+  ]
+ ]
diff --git a/test/LLVM/Test/ExecutionEngine.hs b/test/LLVM/Test/ExecutionEngine.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/ExecutionEngine.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE
+  FlexibleContexts,
+  ForeignFunctionInterface,
+  OverloadedStrings
+  #-}
+module LLVM.Test.ExecutionEngine where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad
+import Data.Functor
+import Data.Maybe
+
+import Foreign.Ptr
+import Data.Word
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.ExecutionEngine
+import LLVM.AST
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import qualified LLVM.AST.IntegerPredicate as IPred
+
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+
+foreign import ccall "dynamic" mkIO32Stub :: FunPtr (Word32 -> IO Word32) -> (Word32 -> IO Word32)
+
+testJIT :: ExecutionEngine e (FunPtr ()) => (Context -> (e -> IO ()) -> IO ()) -> Assertion
+testJIT withEE = withContext $ \context -> withEE context $ \executionEngine -> do
+  let mAST = Module "runSomethingModule" "runSomethingModule" Nothing Nothing [
+              GlobalDefinition $ functionDefaults {
+                G.returnType = i32,
+                G.name = Name "_foo",
+                G.parameters = ([Parameter i32 (Name "bar") []],False),
+                G.basicBlocks = [
+                  BasicBlock (UnName 0) [] (
+                    Do $ Ret (Just (ConstantOperand (C.Int 32 42))) []
+                  )
+                ]
+               }
+              ]
+
+  s <- withModuleFromAST context mAST $ \m -> do
+        withModuleInEngine executionEngine m $ \em -> do
+          Just p <- getFunction em (Name "_foo")
+          (mkIO32Stub ((castFunPtr p) :: FunPtr (Word32 -> IO Word32))) 7
+  s @?= 42
+
+tests = testGroup "ExecutionEngine" [
+  testCase "run something with MCJIT" $ testJIT (\c -> withMCJIT c Nothing Nothing Nothing Nothing)
+ ]
diff --git a/test/LLVM/Test/FunctionAttribute.hs b/test/LLVM/Test/FunctionAttribute.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/FunctionAttribute.hs
@@ -0,0 +1,109 @@
+{-# LANGUAGE LambdaCase #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module LLVM.Test.FunctionAttribute where
+
+import Test.Tasty
+import Test.Tasty.QuickCheck                              hiding ( (.&.) )
+
+import LLVM.Test.Support
+
+import LLVM.AST.FunctionAttribute
+import LLVM.Internal.Coding
+import LLVM.Internal.Context
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.DecodeAST
+import qualified LLVM.Internal.FFI.Attribute              as FFI
+
+import Control.Applicative
+import Data.Bits
+import Data.List
+import Text.Show.Pretty
+import Control.Monad.IO.Class (liftIO)
+import Prelude
+import qualified Data.ByteString.Short                    as B
+
+
+instance Arbitrary FunctionAttribute where
+  arbitrary = oneof
+    [ return AlwaysInline
+    , return ArgMemOnly
+    , return Builtin
+    , return Cold
+    , return Convergent
+    , return InaccessibleMemOnly
+    , return InaccessibleMemOrArgMemOnly
+    , return InlineHint
+    , return JumpTable
+    , return MinimizeSize
+    , return Naked
+    , return NoBuiltin
+    , return NoDuplicate
+    , return NoFree
+    , return NoImplicitFloat
+    , return NoInline
+    , return NonLazyBind
+    , return NoRecurse
+    , return NoRedZone
+    , return NoReturn
+    , return NoUnwind
+    , return OptimizeForSize
+    , return OptimizeNone
+    , return ReadNone
+    , return ReadOnly
+    , return ReturnsTwice
+    , return SafeStack
+    , return SanitizeAddress
+    , return SanitizeHWAddress
+    , return SanitizeMemory
+    , return SanitizeThread
+    , return Speculatable
+    , return StackProtect
+    , return StackProtectReq
+    , return StackProtectStrong
+    , return StrictFP
+    , return UWTable
+    , return WriteOnly
+    , StackAlignment <$> elements (map (2^) [0..8 :: Int])
+    , StringAttribute <$> (B.pack <$> arbitrary) <*> (B.pack <$> arbitrary)
+    , suchThat (AllocSize <$> arbitrary <*> arbitrary) (/= AllocSize 0 (Just 0))
+    ]
+
+  shrink = \case
+    StackAlignment x    -> map StackAlignment (nub [ v | u <- shrink x, let v = ceilPow2 u, v /= x ])
+    StringAttribute x y -> [ StringAttribute (B.pack x') y | x' <- shrink (B.unpack x) ]
+                        ++ [ StringAttribute x (B.pack y') | y' <- shrink (B.unpack y) ]
+    AllocSize x y       -> [ AllocSize x' y | x' <- shrink x, not (x' == 0 && y == Just 0) ]
+                        ++ [ AllocSize x y' | y' <- shrink y, not (x == 0 && y' == Just 0) ]
+    _                   -> []
+
+
+tests :: TestTree
+tests =
+  testGroup "FunctionAttribute"
+    [ testProperty "round-trip"  $ \attr ->
+        ioProperty $ withContext $ \ctx  -> do
+          attr' <- runEncodeAST ctx $ do
+            attrSet <- encodeM [attr] :: EncodeAST FFI.FunctionAttributeSet
+            liftIO (runDecodeAST (decodeM attrSet :: DecodeAST [FunctionAttribute]))
+          return $ counterexample (unlines [ "expected: " ++ ppShow [attr]
+                                           , "but got:  " ++ ppShow attr'
+                                           ])
+                                  ([attr] == attr')
+    ]
+
+
+isPow2 :: (Bits a, Num a) => a -> Bool
+isPow2 0 = True
+isPow2 1 = False
+isPow2 n = n .&. (n - 1) == 0
+
+ceilPow2 :: (Bits a, Integral a) => a -> a
+ceilPow2 n
+  | isPow2 n  = n
+  | otherwise =
+      let x = logBase 2 (fromIntegral n) :: Double
+          y = floor x + 1
+      in
+      1 `shiftL` y
+
diff --git a/test/LLVM/Test/Global.hs b/test/LLVM/Test/Global.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Global.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Global where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import Data.Monoid
+import qualified Data.ByteString.Char8 as ByteString
+import Data.ByteString.Short (fromShort)
+
+import LLVM.Test.Support
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.AST
+import LLVM.AST.Type as A.T
+import qualified LLVM.AST.Global as G
+
+tests = testGroup "Global" [
+  testGroup "Alignment" [
+    testCase name $ withContext $ \context -> do
+      let ast = Module "<string>" "<string>" Nothing Nothing [ GlobalDefinition g ]
+      ast' <- withModuleFromAST context ast moduleAST
+      ast' @?= ast
+    | a <- [0,1],
+      s <- [Nothing, Just "foo"],
+      g <- [
+       globalVariableDefaults {
+        G.name = UnName 0,
+        G.type' = i32,
+        G.alignment = a,
+        G.section = s
+        },
+       functionDefaults {
+         G.returnType = A.T.void,
+         G.name = UnName 0,
+         G.parameters = ([], False),
+         G.alignment = a,
+         G.section = s
+       }
+       ],
+      let
+          gn (G.Function {}) = "function"
+          gn (G.GlobalVariable {}) = "variable"
+          name = gn g <> ", align " <> show a <> (maybe "" (("  section " <>) . ByteString.unpack . fromShort) s)
+   ]
+ ]
diff --git a/test/LLVM/Test/IRBuilder.hs b/test/LLVM/Test/IRBuilder.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/IRBuilder.hs
@@ -0,0 +1,635 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecursiveDo #-}
+module LLVM.Test.IRBuilder
+  ( tests
+  ) where
+
+import           Test.Tasty
+import           Test.Tasty.HUnit
+
+import           LLVM.AST hiding (function)
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.Float as F
+import qualified LLVM.AST.Global
+import           LLVM.AST.Linkage (Linkage(..))
+import qualified LLVM.AST.Type as AST
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Instruction as I (function)
+import           LLVM.IRBuilder
+
+tests :: TestTree
+tests =
+  testGroup "IRBuilder" [
+    testGroup "module builder"
+      [ testCase "builds the simple module" $
+        simple @?=
+        defaultModule {
+          moduleName = "exampleModule",
+          moduleDefinitions =
+            [ GlobalDefinition functionDefaults {
+                LLVM.AST.Global.name = "add",
+                LLVM.AST.Global.parameters =
+                  ( [ Parameter AST.i32 "a_0" []
+                    , Parameter AST.i32 "b_0" []
+                    ]
+                  , False
+                  ),
+                LLVM.AST.Global.returnType = AST.i32,
+                LLVM.AST.Global.basicBlocks =
+                  [ BasicBlock
+                      "entry_0"
+                      [ UnName 0 := Add {
+                          operand0 = LocalReference AST.i32 "a_0",
+                          operand1 = LocalReference AST.i32 "b_0",
+                          nsw = False,
+                          nuw = False,
+                          metadata = []
+                        }
+                      ]
+                      (Do (Ret (Just (LocalReference AST.i32 (UnName 0))) []))
+                  ]
+              }
+            ]
+        }
+      , testCase "calls constant globals" callWorksWithConstantGlobals
+      , testCase "supports recursive function calls" recursiveFunctionCalls
+      , testCase "resolves typedefs" resolvesTypeDefs
+      , testCase "resolves constant typedefs" resolvesConstantTypeDefs
+      , testCase "handling of terminator" terminatorHandling
+      , testCase "builds the example" $ do
+        let f10 = ConstantOperand (C.Float (F.Double 10))
+            fadd a b = FAdd { operand0 = a, operand1 = b, fastMathFlags = noFastMathFlags, metadata = [] }
+            add a b = Add { operand0 = a, operand1 = b, nsw = False, nuw = False, metadata = [] }
+        example @?=
+          defaultModule {
+            moduleName = "exampleModule",
+            moduleDefinitions =
+              [ GlobalDefinition functionDefaults {
+                  LLVM.AST.Global.name = "foo",
+                  LLVM.AST.Global.returnType = AST.double,
+                  LLVM.AST.Global.basicBlocks =
+                    [ BasicBlock (UnName 0) [ "xxx_0" := fadd f10 f10]
+                        (Do (Ret Nothing []))
+                    , BasicBlock
+                        "blk_0"
+                        [ UnName 1 := fadd f10 f10
+                        , UnName 2 := fadd (LocalReference AST.double (UnName 1)) (LocalReference AST.double (UnName 1))
+                        , UnName 3 := add (ConstantOperand (C.Int 32 10)) (ConstantOperand (C.Int 32 10))
+                        ]
+                        (Do (Br "blk_1" []))
+                    , BasicBlock
+                        "blk_1"
+                        [ "c_0" := fadd f10 f10
+                        , UnName 4 := fadd (LocalReference AST.double "c_0") (LocalReference AST.double "c_0")
+                        ]
+                        (Do (Br "blk_2" []))
+                    , BasicBlock
+                        "blk_2"
+                        [ "phi_0" :=
+                            Phi
+                              AST.double
+                              [ ( f10, "blk_0" )
+                              , ( f10, "blk_1" )
+                              , ( f10, "blk_2" )
+                              ]
+                              []
+                        , UnName 5 := fadd f10 f10
+                        , UnName 6 := fadd (LocalReference AST.double (UnName 5)) (LocalReference AST.double (UnName 5))
+                        ]
+                        (Do (Ret Nothing []))
+                    ]
+                }
+              , GlobalDefinition functionDefaults {
+                  LLVM.AST.Global.name = "bar",
+                  LLVM.AST.Global.returnType = AST.double,
+                  LLVM.AST.Global.basicBlocks =
+                    [ BasicBlock
+                       (UnName 0)
+                       [ UnName 1 := fadd f10 f10
+                       , UnName 2 := fadd (LocalReference AST.double (UnName 1)) (LocalReference AST.double (UnName 1))
+                       ]
+                       (Do (Ret Nothing []))
+                    ]
+                }
+              , GlobalDefinition functionDefaults {
+                  LLVM.AST.Global.name = "baz",
+                  LLVM.AST.Global.parameters =
+                    ( [ Parameter AST.i32 (UnName 0) []
+                      , Parameter AST.double "arg_0" []
+                      , Parameter AST.i32 (UnName 1) []
+                      , Parameter AST.double "arg_1" []]
+                    , False),
+                  LLVM.AST.Global.returnType = AST.double,
+                  LLVM.AST.Global.basicBlocks =
+                    [ BasicBlock
+                        (UnName 2)
+                        []
+                        (Do
+                           (Switch
+                             (LocalReference AST.i32 (UnName 1))
+                             (UnName 3)
+                             [ ( C.Int 32 0, UnName 4), ( C.Int 32 1, UnName 7) ] []))
+                    , BasicBlock
+                        (UnName 3)
+                        []
+                        (Do (Br (UnName 4) []))
+                    , BasicBlock
+                        (UnName 4)
+                        [ "arg_2" := fadd (LocalReference AST.double "arg_0") f10
+                        , UnName 5 := fadd (LocalReference AST.double "arg_2") (LocalReference AST.double "arg_2")
+                        , UnName 6 := Select {
+                            condition' = ConstantOperand (C.Int 1 0),
+                            trueValue = LocalReference AST.double "arg_2",
+                            falseValue = LocalReference AST.double (UnName 5),
+                            metadata = []
+                          }
+                        ]
+                        (Do (Ret Nothing []))
+                    , BasicBlock
+                        (UnName 7)
+                        [ UnName 8 := GetElementPtr {
+                            inBounds = False,
+                            address = ConstantOperand (C.Null (AST.ptr (AST.ptr (AST.ptr AST.i32)))),
+                            indices =
+                              [ ConstantOperand (C.Int 32 10)
+                              , ConstantOperand (C.Int 32 20)
+                              , ConstantOperand (C.Int 32 30)
+                              ],
+                            metadata = []
+                          }
+                        , UnName 9 := GetElementPtr {
+                            inBounds = False,
+                            address = LocalReference (AST.ptr AST.i32) (UnName 8),
+                            indices = [ ConstantOperand (C.Int 32 40) ],
+                            metadata = []
+                          }
+                        ]
+                        (Do (Ret Nothing []))
+                    ]
+                }
+              ]
+          }
+      ]
+  ]
+
+recursiveFunctionCalls :: Assertion
+recursiveFunctionCalls = do
+  m @?= defaultModule
+    { moduleName = "exampleModule"
+    , moduleDefinitions =
+      [ GlobalDefinition functionDefaults
+          { LLVM.AST.Global.returnType = AST.i32
+          , LLVM.AST.Global.name = Name "f"
+          , LLVM.AST.Global.parameters = ([Parameter AST.i32 "a_0" []], False)
+          , LLVM.AST.Global.basicBlocks =
+              [ BasicBlock (Name "entry_0")
+                 [ UnName 0 := Call
+                    { tailCallKind = Nothing
+                    , callingConvention = CC.C
+                    , returnAttributes = []
+                    , I.function =
+                        Right (ConstantOperand (C.GlobalReference (AST.ptr (FunctionType AST.i32 [AST.i32] False)) (Name "f")))
+                    , arguments = [(LocalReference (IntegerType {typeBits = 32}) (Name "a_0"),[])]
+                    , functionAttributes = []
+                    , metadata = []
+                    }
+                 ]
+                 (Do (Ret (Just (LocalReference AST.i32 (UnName 0))) []))
+              ]
+          }
+      ]
+    }
+  where
+    m = buildModule "exampleModule" $ mdo
+      f <- function "f" [(AST.i32, "a")] AST.i32 $ \[a] -> mdo
+        entry <- block `named` "entry"; do
+          c <- call f [(a, [])]
+          ret c
+      pure ()
+
+callWorksWithConstantGlobals :: Assertion
+callWorksWithConstantGlobals = do
+  funcCall @?= defaultModule
+    { moduleName = "exampleModule"
+    , moduleDefinitions =
+      [ GlobalDefinition functionDefaults {
+          LLVM.AST.Global.returnType = AST.ptr AST.i8,
+          LLVM.AST.Global.name = Name "malloc",
+          LLVM.AST.Global.parameters = ([Parameter (IntegerType {typeBits = 64}) (Name "") []],False),
+          LLVM.AST.Global.basicBlocks = []
+        }
+      , GlobalDefinition functionDefaults {
+          LLVM.AST.Global.returnType = VoidType,
+          LLVM.AST.Global.name = Name "omg",
+          LLVM.AST.Global.parameters = ([],False),
+          LLVM.AST.Global.basicBlocks = [
+            BasicBlock (UnName 0) [
+              UnName 1 := Call { tailCallKind = Nothing
+                , I.function = Right (
+                  ConstantOperand (
+                    C.GlobalReference
+                      (AST.ptr $ FunctionType {resultType = AST.ptr $ IntegerType {typeBits = 8}, argumentTypes = [IntegerType {typeBits = 64}], isVarArg = False})
+                      (Name "malloc")
+                    )
+                  )
+                , callingConvention = CC.C
+                , returnAttributes = []
+                , arguments = [(ConstantOperand (C.Int {C.integerBits = 64, C.integerValue = 10}),[])]
+                , functionAttributes = []
+                , metadata = []
+                }
+              ]
+              (Do (Unreachable {metadata' = []}))
+          ]
+        }
+      ]
+    }
+
+resolvesTypeDefs :: Assertion
+resolvesTypeDefs = do
+  buildModule "<string>" builder @?= ast
+  where builder = mdo
+          pairTy <- typedef "pair" (Just (StructureType False [AST.i32, AST.i32]))
+          function "f" [(AST.ptr pairTy, "ptr"), (AST.i32, "x"), (AST.i32, "y")] AST.void $ \[ptr, x, y] -> do
+            xPtr <- gep ptr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)]
+            yPtr <- gep ptr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)]
+            store xPtr 0 x
+            store yPtr 0 y
+          function "g" [(pairTy, "pair")] AST.i32 $ \[pair] -> do
+            x <- extractValue pair [0]
+            y <- extractValue pair [1]
+            z <- add x y
+            ret z
+          pure ()
+        ast = defaultModule
+          { moduleName = "<string>"
+          , moduleDefinitions =
+            [ TypeDefinition "pair" (Just (StructureType False [AST.i32, AST.i32]))
+            , GlobalDefinition functionDefaults
+              { LLVM.AST.Global.name = "f"
+              , LLVM.AST.Global.parameters = ( [ Parameter (AST.ptr (NamedTypeReference "pair")) "ptr_0" []
+                               , Parameter AST.i32 "x_0" []
+                               , Parameter AST.i32 "y_0" []]
+                             , False)
+              , LLVM.AST.Global.returnType = AST.void
+              , LLVM.AST.Global.basicBlocks =
+                [ BasicBlock (UnName 0)
+                  [ UnName 1 := GetElementPtr
+                      { inBounds = False
+                      , address = LocalReference (AST.ptr (NamedTypeReference "pair")) "ptr_0"
+                      , indices = [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)]
+                      , metadata = []
+                      }
+                  , UnName 2 := GetElementPtr
+                      { inBounds = False
+                      , address = LocalReference (AST.ptr (NamedTypeReference "pair")) "ptr_0"
+                      , indices = [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)]
+                      , metadata = []
+                      }
+                  , Do $ Store
+                      { volatile = False
+                      , address = LocalReference (AST.ptr AST.i32) (UnName 1)
+                      , value = LocalReference AST.i32 "x_0"
+                      , maybeAtomicity = Nothing
+                      , alignment = 0
+                      , metadata = []
+                      }
+                  , Do $ Store
+                      { volatile = False
+                      , address = LocalReference (AST.ptr AST.i32) (UnName 2)
+                      , value = LocalReference AST.i32 "y_0"
+                      , maybeAtomicity = Nothing
+                      , alignment = 0
+                      , metadata = []
+                      }
+                  ]
+                  (Do (Ret Nothing []))
+                ]
+              }
+            , GlobalDefinition functionDefaults
+              { LLVM.AST.Global.name = "g"
+              , LLVM.AST.Global.parameters = ( [Parameter (NamedTypeReference "pair") "pair_0" []]
+                             , False)
+              , LLVM.AST.Global.returnType = AST.i32
+              , LLVM.AST.Global.basicBlocks =
+                [ BasicBlock (UnName 0)
+                  [ UnName 1 := ExtractValue
+                      { aggregate = LocalReference (NamedTypeReference "pair") "pair_0"
+                      , indices' = [0]
+                      , metadata = []
+                      }
+                  , UnName 2 := ExtractValue
+                      { aggregate = LocalReference (NamedTypeReference "pair") "pair_0"
+                      , indices' = [1]
+                      , metadata = []
+                      }
+                  , UnName 3 := Add
+                      { nsw = False
+                      , nuw = False
+                      , operand0 = LocalReference AST.i32 (UnName 1)
+                      , operand1 = LocalReference AST.i32 (UnName 2)
+                      , metadata = []
+                      }
+                  ]
+                  (Do (Ret (Just (LocalReference AST.i32 (UnName 3))) []))
+                ]
+              }
+            ]}
+
+resolvesConstantTypeDefs :: Assertion
+resolvesConstantTypeDefs = do
+  buildModule "<string>" builder @?= ast
+  where builder = mdo
+          pairTy <- typedef "pair" (Just (StructureType False [AST.i32, AST.i32]))
+          globalPair <- global "gpair" pairTy (C.AggregateZero pairTy)
+          function "f" [(AST.i32, "x"), (AST.i32, "y")] AST.void $ \[x, y] -> do
+            let ptr = ConstantOperand $ C.GlobalReference (AST.ptr pairTy) "gpair"
+            xPtr <- gep ptr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)]
+            yPtr <- gep ptr [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)]
+            store xPtr 0 x
+            store yPtr 0 y
+          function "g" [] AST.i32 $ \[] -> do
+            pair <- load (ConstantOperand $ C.GlobalReference (AST.ptr pairTy) "gpair") 0
+            x <- extractValue pair [0]
+            y <- extractValue pair [1]
+            z <- add x y
+            ret z
+          pure ()
+        ast = defaultModule
+          { moduleName = "<string>"
+          , moduleDefinitions =
+            [ TypeDefinition "pair" (Just (StructureType False [AST.i32, AST.i32]))
+            , GlobalDefinition globalVariableDefaults
+              { LLVM.AST.Global.name = "gpair"
+              , LLVM.AST.Global.type' = NamedTypeReference "pair"
+              , LLVM.AST.Global.linkage = External
+              , LLVM.AST.Global.initializer = Just (C.AggregateZero (NamedTypeReference "pair"))
+              }
+            , GlobalDefinition functionDefaults
+              { LLVM.AST.Global.name = "f"
+              , LLVM.AST.Global.parameters = ( [ Parameter AST.i32 "x_0" []
+                                               , Parameter AST.i32 "y_0" []]
+                             , False)
+              , LLVM.AST.Global.returnType = AST.void
+              , LLVM.AST.Global.basicBlocks =
+                [ BasicBlock (UnName 0)
+                  [ UnName 1 := GetElementPtr
+                      { inBounds = False
+                      , address = ConstantOperand (C.GlobalReference (AST.ptr (NamedTypeReference "pair")) "gpair")
+                      , indices = [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 0)]
+                      , metadata = []
+                      }
+                  , UnName 2 := GetElementPtr
+                      { inBounds = False
+                      , address = ConstantOperand (C.GlobalReference (AST.ptr (NamedTypeReference "pair")) "gpair")
+                      , indices = [ConstantOperand (C.Int 32 0), ConstantOperand (C.Int 32 1)]
+                      , metadata = []
+                      }
+                  , Do $ Store
+                      { volatile = False
+                      , address = LocalReference (AST.ptr AST.i32) (UnName 1)
+                      , value = LocalReference AST.i32 "x_0"
+                      , maybeAtomicity = Nothing
+                      , alignment = 0
+                      , metadata = []
+                      }
+                  , Do $ Store
+                      { volatile = False
+                      , address = LocalReference (AST.ptr AST.i32) (UnName 2)
+                      , value = LocalReference AST.i32 "y_0"
+                      , maybeAtomicity = Nothing
+                      , alignment = 0
+                      , metadata = []
+                      }
+                  ]
+                  (Do (Ret Nothing []))
+                ]
+              }
+            , GlobalDefinition functionDefaults
+              { LLVM.AST.Global.name = "g"
+              , LLVM.AST.Global.parameters = ([], False)
+              , LLVM.AST.Global.returnType = AST.i32
+              , LLVM.AST.Global.basicBlocks =
+                [ BasicBlock (UnName 0)
+                  [ UnName 1 := Load
+                      { volatile = False,
+                        address = ConstantOperand (C.GlobalReference (AST.ptr (NamedTypeReference "pair")) "gpair"),
+                        maybeAtomicity = Nothing,
+                        alignment = 0,
+                        metadata = []
+                      }
+                  , UnName 2 := ExtractValue
+                      { aggregate = LocalReference (NamedTypeReference "pair") (UnName 1)
+                      , indices' = [0]
+                      , metadata = []
+                      }
+                  , UnName 3 := ExtractValue
+                      { aggregate = LocalReference (NamedTypeReference "pair") (UnName 1)
+                      , indices' = [1]
+                      , metadata = []
+                      }
+                  , UnName 4 := Add
+                      { nsw = False
+                      , nuw = False
+                      , operand0 = LocalReference AST.i32 (UnName 2)
+                      , operand1 = LocalReference AST.i32 (UnName 3)
+                      , metadata = []
+                      }
+                  ]
+                  (Do (Ret (Just (LocalReference AST.i32 (UnName 4))) []))
+                ]
+              }
+            ]}
+
+terminatorHandling :: Assertion
+terminatorHandling = do
+  firstTerminatorWins @?= firstWinsAst
+  terminatorsCompose @?= terminatorsComposeAst
+  nestedControlFlowWorks @?= nestedControlFlowAst
+  where
+    firstTerminatorWins = buildModule "firstTerminatorWinsModule" $ mdo
+      function "f" [(AST.i32, "a"), (AST.i32, "b")] AST.i32 $ \[a, b] -> mdo
+
+        entry <- block `named` "entry"; do
+          c <- add a b
+          d <- add a c
+          ret c
+          ret d
+    terminatorsCompose = buildModule "terminatorsComposeModule" $ mdo
+      function "f" [(AST.i1, "a")] AST.i1 $ \[a] -> mdo
+
+        entry <- block `named` "entry"; do
+          if' a $ do
+            ret (bit 0)
+
+          ret (bit 1)
+    nestedControlFlowWorks = buildModule "nestedControlFlowWorksModule" $ mdo
+      function "f" [(AST.i1, "a"), (AST.i1, "b")] AST.i1 $ \[a, b] -> mdo
+
+        entry <- block `named` "entry"; do
+          if' a $ do
+            if' b $ do
+              ret (bit 0)
+
+          ret (bit 1)
+    if' cond asm = mdo
+      condBr cond ifBlock end
+      ifBlock <- block `named` "if.begin"
+      asm
+      br end
+      end <- block `named` "if.end"
+      return ()
+
+    firstWinsAst = defaultModule
+      { moduleName = "firstTerminatorWinsModule"
+      , moduleDefinitions =
+        [ GlobalDefinition functionDefaults
+          { LLVM.AST.Global.name = "f"
+          , LLVM.AST.Global.parameters = ([ Parameter AST.i32 "a_0" [], Parameter AST.i32 "b_0" []], False)
+          , LLVM.AST.Global.returnType = AST.i32
+          , LLVM.AST.Global.basicBlocks =
+            [ BasicBlock (Name "entry_0")
+              [ UnName 0 := Add { nsw = False, nuw = False, metadata = []
+                                , operand0 = LocalReference (IntegerType {typeBits = 32}) (Name "a_0")
+                                , operand1 = LocalReference (IntegerType {typeBits = 32}) (Name "b_0")
+                                }
+              , UnName 1 := Add { nsw = False, nuw = False, metadata = []
+                                , operand0 = LocalReference (IntegerType {typeBits = 32}) (Name "a_0")
+                                , operand1 = LocalReference (IntegerType {typeBits = 32}) (UnName 0)
+                                }
+              ]
+              (Do (Ret {returnOperand = Just (LocalReference (IntegerType {typeBits = 32}) (UnName 0)), metadata' = []}))]
+          }
+        ]}
+    terminatorsComposeAst = defaultModule
+      { moduleName = "terminatorsComposeModule"
+      , moduleDefinitions =
+        [ GlobalDefinition functionDefaults
+          { LLVM.AST.Global.name = "f"
+          , LLVM.AST.Global.parameters = ([ Parameter AST.i1 "a_0" []], False)
+          , LLVM.AST.Global.returnType = AST.i1
+          , LLVM.AST.Global.basicBlocks =
+            [ BasicBlock (Name "entry_0")
+              []
+              (Do (CondBr {condition = LocalReference (IntegerType {typeBits = 1}) (Name "a_0")
+                          , trueDest = Name "if.begin_0"
+                          , falseDest = Name "if.end_0", metadata' = []}))
+                          , BasicBlock (Name "if.begin_0")
+                            []
+                            (Do (Ret {returnOperand = Just (ConstantOperand (C.Int {C.integerBits = 1, C.integerValue = 0})), metadata' = []}))
+                          , BasicBlock (Name "if.end_0")
+                            []
+                            (Do (Ret {returnOperand = Just (ConstantOperand (C.Int {C.integerBits = 1, C.integerValue = 1})), metadata' = []}))]
+          }
+        ]}
+    nestedControlFlowAst = defaultModule
+      { moduleName = "nestedControlFlowWorksModule"
+      , moduleDefinitions =
+        [ GlobalDefinition functionDefaults
+          { LLVM.AST.Global.name = "f"
+          , LLVM.AST.Global.parameters = ([ Parameter AST.i1 "a_0" [], Parameter AST.i1 "b_0" []], False)
+          , LLVM.AST.Global.returnType = AST.i1
+          , LLVM.AST.Global.basicBlocks =
+            [ BasicBlock (Name "entry_0")
+              []
+              (Do (CondBr { condition = LocalReference (IntegerType {typeBits = 1}) (Name "a_0")
+                          , trueDest = Name "if.begin_0"
+                          , falseDest = Name "if.end_1"
+                          , metadata' = []}))
+                          , BasicBlock (Name "if.begin_0") [] (Do (CondBr { condition = LocalReference (IntegerType {typeBits = 1}) (Name "b_0")
+                                                                          , trueDest = Name "if.begin_1"
+                                                                          , falseDest = Name "if.end_0"
+                                                                          , metadata' = []}))
+                                                                          , BasicBlock (Name "if.begin_1") [] (Do (Ret {returnOperand = Just (ConstantOperand (C.Int {C.integerBits = 1, C.integerValue = 0})), metadata' = []}))
+                                                                          , BasicBlock (Name "if.end_0") [] (Do (Br {dest = Name "if.end_1", metadata' = []}))
+                          , BasicBlock (Name "if.end_1") [] (Do (Ret {returnOperand = Just (ConstantOperand (C.Int {C.integerBits = 1, C.integerValue = 1})), metadata' = []}))
+            ]
+          }
+        ]}
+
+simple :: Module
+simple = buildModule "exampleModule" $ mdo
+
+  function "add" [(AST.i32, "a"), (AST.i32, "b")] AST.i32 $ \[a, b] -> mdo
+
+    entry <- block `named` "entry"; do
+      c <- add a b
+      ret c
+
+example :: Module
+example = mkModule $ execModuleBuilder emptyModuleBuilder $ mdo
+
+  foo <- function "foo" [] AST.double $ \_ -> mdo
+    xxx <- fadd c1 c1 `named` "xxx"
+
+    blk1 <- block `named` "blk"; do
+      a <- fadd c1 c1
+      b <- fadd a a
+      c <- add c2 c2
+      br blk2
+
+    blk2 <- block `named` "blk"; do
+      a <- fadd c1 c1 `named` "c"
+      b <- fadd a a
+      br blk3
+
+    blk3 <- block `named` "blk"; do
+      l <- phi [(c1, blk1), (c1, blk2), (c1, blk3)] `named` "phi"
+      a <- fadd c1 c1
+      b <- fadd a a
+      retVoid
+
+    pure ()
+
+
+  function "bar" [] AST.double $ \_ -> mdo
+
+    blk3 <- block; do
+      a <- fadd c1 c1
+      b <- fadd a a
+      retVoid
+
+    pure ()
+
+  function "baz" [(AST.i32, NoParameterName), (AST.double, "arg"), (AST.i32, NoParameterName), (AST.double, "arg")] AST.double $ \[rrr, arg, arg2, arg3] -> mdo
+
+    switch arg2 blk1 [(C.Int 32 0, blk2), (C.Int 32 1, blk3)]
+
+    blk1 <- block; do
+      br blk2
+
+    blk2 <- block; do
+      a <- fadd arg c1 `named` "arg"
+      b <- fadd a a
+      select (cons $ C.Int 1 0) a b
+      retVoid
+
+    blk3 <- block; do
+      let nul = cons $ C.Null $ AST.ptr $ AST.ptr $ AST.ptr $ IntegerType 32
+      addr <- gep nul [cons $ C.Int 32 10, cons $ C.Int 32 20, cons $ C.Int 32 30]
+      addr' <- gep addr [cons $ C.Int 32 40]
+      retVoid
+
+    pure ()
+  where
+    mkModule ds = defaultModule { moduleName = "exampleModule", moduleDefinitions = ds }
+    cons = ConstantOperand
+
+funcCall :: Module
+funcCall = mkModule $ execModuleBuilder emptyModuleBuilder $ mdo
+  extern "malloc" [AST.i64] (AST.ptr AST.i8)
+
+  let mallocTy = AST.ptr $ AST.FunctionType (AST.ptr AST.i8) [AST.i64] False
+
+  function "omg" [] (AST.void) $ \_ -> do
+    let size = int64 10
+    call (ConstantOperand $ C.GlobalReference mallocTy "malloc") [(size, [])]
+    unreachable
+  where
+  mkModule ds = defaultModule { moduleName = "exampleModule", moduleDefinitions = ds }
+
+c1 :: Operand
+c1 = ConstantOperand $ C.Float (F.Double 10)
+
+c2 :: Operand
+c2 = ConstantOperand $ C.Int 32 10
diff --git a/test/LLVM/Test/InlineAssembly.hs b/test/LLVM/Test/InlineAssembly.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/InlineAssembly.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.InlineAssembly where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import LLVM.Context
+import LLVM.Module
+
+import LLVM.AST
+import LLVM.AST.Type
+import LLVM.AST.InlineAssembly as IA
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.Global as G
+
+tests = testGroup "InlineAssembly" [
+  testCase "expression" $ do
+    let ast = Module "<string>" "<string>" Nothing Nothing [
+                GlobalDefinition $ 
+                  functionDefaults {
+                    G.returnType = i32,
+                    G.name = Name "foo",
+                    G.parameters = ([Parameter i32 (Name "x") []],False),
+                    G.basicBlocks = [
+                      BasicBlock (UnName 0) [
+                        UnName 1 := Call {
+                          tailCallKind = Nothing,
+                          callingConvention = CC.C,
+                          returnAttributes = [],
+                          function = Left $ InlineAssembly {
+                                       IA.type' = FunctionType i32 [i32] False,
+                                       assembly = "bswap $0",
+                                       constraints = "=r,r",
+                                       hasSideEffects = False,
+                                       alignStack = False,
+                                       dialect = ATTDialect
+                                     },
+                          arguments = [
+                            (LocalReference i32 (Name "x"), [])
+                           ],
+                          functionAttributes = [],
+                          metadata = []
+                        }
+                      ] (
+                        Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+                      )
+                    ]
+                }
+
+              ]
+        s = "; ModuleID = '<string>'\n\
+             \source_filename = \"<string>\"\n\
+             \\n\
+             \define i32 @foo(i32 %x) {\n\
+             \  %1 = call i32 asm \"bswap $0\", \"=r,r\"(i32 %x)\n\
+             \  ret i32 %1\n\
+             \}\n"
+    strCheck ast s,
+
+  testCase "module" $ do
+    let ast = Module "<string>" "<string>" Nothing Nothing [
+                ModuleInlineAssembly "foo",
+                ModuleInlineAssembly "bar",
+                GlobalDefinition $ globalVariableDefaults {
+                  G.name = UnName 0,
+                  G.type' = i32
+                }
+              ]
+        s = "; ModuleID = '<string>'\n\
+             \source_filename = \"<string>\"\n\
+             \\n\
+             \module asm \"foo\"\n\
+             \module asm \"bar\"\n\
+             \\n\
+             \@0 = external global i32\n"
+    strCheck ast s
+ ]
diff --git a/test/LLVM/Test/Instructions.hs b/test/LLVM/Test/Instructions.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Instructions.hs
@@ -0,0 +1,1279 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module LLVM.Test.Instructions where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck (Arbitrary(..), (===), ioProperty, oneof, testProperty)
+
+import LLVM.Test.Support
+
+import Control.Monad
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as ByteString
+import Data.Functor
+import Data.List.NonEmpty (NonEmpty((:|)))
+import Data.Maybe
+import Data.Monoid
+import Foreign.Ptr
+import Data.Word
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.Diagnostic
+import LLVM.AST
+import LLVM.AST.Type as A.T
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import qualified LLVM.AST.IntegerPredicate as IPred
+import qualified LLVM.AST.FloatingPointPredicate as FPPred
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.RMWOperation as RMWOp
+
+import LLVM.Internal.Coding (decodeM, encodeM)
+import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
+
+tests = testGroup "Instructions" [
+  testGroup "regular" [
+    testCase name $ do
+      let mAST = Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+              G.returnType = A.T.void,
+              G.name = UnName 0,
+              G.parameters = ([Parameter t (UnName n) [] | (t,n) <- zip ts [0..]], False),
+              G.basicBlocks = [
+                BasicBlock (UnName 7) [
+                  namedInstr
+                 ] (
+                  Do $ Ret Nothing []
+                 )
+               ]
+            }
+           ]
+          mStr = "; ModuleID = '<string>'\n\
+                 \source_filename = \"<string>\"\n\
+                 \\n\
+                 \define void @0(i32 %0, float %1, i32* %2, i64 %3, i1 %4, <2 x i32> %5, { i32, i32 } %6) {\n\
+                 \  " <> namedInstrS <> "\n\
+                 \  ret void\n\
+                 \}\n"
+      strCheck mAST mStr
+    | let ts = [
+           i32,
+           float,
+           ptr i32,
+           i64,
+           i1,
+           VectorType 2 i32,
+           StructureType False [i32, i32]
+           ],
+      let a i = LocalReference (ts !! fromIntegral i) (UnName i),
+      (name, namedInstr, namedInstrS :: ByteString) <- (
+        [
+         (name, UnName 8 := instr, "%8 = " <> instrS)
+         | (name, instr, instrS) <- [
+          --("fneg",
+          -- FNeg {
+          --   fastMathFlags = noFastMathFlags,
+          --   operand0 = a 1,
+          --   metadata = []
+          -- },
+          -- "fneg float %1"),
+          ("add",
+           Add {
+             nsw = False,
+             nuw = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "add i32 %0, %0"),
+          ("nsw",
+           Add {
+             nsw = True,
+             nuw = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "add nsw i32 %0, %0"),
+          ("nuw",
+           Add {
+             nsw = False,
+             nuw = True,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "add nuw i32 %0, %0"),
+          ("fadd",
+           FAdd {
+             fastMathFlags = noFastMathFlags,
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "fadd float %1, %1"),
+          ("sub",
+           Sub {
+             nsw = False,
+             nuw = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "sub i32 %0, %0"),
+          ("fsub",
+           FSub {
+             fastMathFlags = noFastMathFlags,
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "fsub float %1, %1"),
+          ("mul",
+           Mul {
+             nsw = False,
+             nuw = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "mul i32 %0, %0"),
+          ("fmul",
+           FMul {
+             fastMathFlags = noFastMathFlags,
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "fmul float %1, %1"),
+          ("udiv",
+           UDiv {
+             exact = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "udiv i32 %0, %0"),
+          ("exact",
+           UDiv {
+             exact = True,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "udiv exact i32 %0, %0"),
+          ("sdiv",
+           SDiv {
+             exact = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "sdiv i32 %0, %0"),
+          ("fdiv",
+           FDiv {
+             fastMathFlags = noFastMathFlags,
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "fdiv float %1, %1"),
+          ("urem",
+           URem {
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "urem i32 %0, %0"),
+          ("srem",
+           SRem {
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "srem i32 %0, %0"),
+          ("frem",
+           FRem {
+             fastMathFlags = noFastMathFlags,
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "frem float %1, %1"),
+          ("frem fast",
+           FRem {
+             fastMathFlags = FastMathFlags {
+                 allowReassoc = True,
+                 noNaNs = True,
+                 noInfs = True,
+                 noSignedZeros = True,
+                 allowReciprocal = True,
+                 allowContract = True,
+                 approxFunc = True
+             },
+             operand0 = a 1,
+             operand1 = a 1,
+             metadata = []
+           },
+           "frem fast float %1, %1"),
+          ("shl",
+           Shl {
+             nsw = False,
+             nuw = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "shl i32 %0, %0"),
+          ("ashr",
+           AShr {
+             exact = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "ashr i32 %0, %0"),
+          ("lshr",
+           LShr {
+             exact = False,
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "lshr i32 %0, %0"),
+          ("and",
+           And {
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "and i32 %0, %0"),
+          ("or",
+           Or {
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "or i32 %0, %0"),
+          ("xor",
+           Xor {
+             operand0 = a 0,
+             operand1 = a 0,
+             metadata = []
+           },
+           "xor i32 %0, %0"),
+          ("alloca",
+           Alloca {
+             allocatedType = i32,
+             numElements = Nothing,
+             alignment = 4,
+             metadata = []
+           },
+           "alloca i32, align 4"),
+          ("alloca tricky",
+           Alloca {
+             allocatedType = IntegerType 7,
+             numElements = Just (ConstantOperand (C.Int 32 2)),
+             alignment = 128,
+             metadata = []
+           },
+           "alloca i7, i32 2, align 128"),
+          ("load",
+           Load {
+             volatile = False,
+             address = a 2,
+             maybeAtomicity = Nothing,
+             alignment = 4,
+             metadata = []
+           },
+           "load i32, i32* %2, align 4"),
+          ("volatile",
+           Load {
+             volatile = True,
+             address = a 2,
+             maybeAtomicity = Nothing,
+             alignment = 4,
+             metadata = []
+           },
+           "load volatile i32, i32* %2, align 4"),
+          ("acquire",
+           Load {
+             volatile = False,
+             address = a 2,
+             maybeAtomicity = Just (System, Acquire),
+             alignment = 1,
+             metadata = []
+           },
+           "load atomic i32, i32* %2 acquire, align 1"),
+          ("singlethread",
+           Load {
+             volatile = False,
+             address = a 2,
+             maybeAtomicity = Just (SingleThread, Monotonic),
+             alignment = 1,
+             metadata = []
+           },
+           "load atomic i32, i32* %2 syncscope(\"singlethread\") monotonic, align 1"),
+          ("GEP",
+           GetElementPtr {
+             inBounds = False,
+             address = a 2,
+             indices = [ a 0 ],
+             metadata = []
+           },
+           "getelementptr i32, i32* %2, i32 %0"),
+          ("inBounds",
+           GetElementPtr {
+             inBounds = True,
+             address = a 2,
+             indices = [ a 0 ],
+             metadata = []
+           },
+           "getelementptr inbounds i32, i32* %2, i32 %0"),
+          ("cmpxchg",
+           CmpXchg {
+             volatile = False,
+             address = a 2,
+             expected = a 0,
+             replacement = a 0,
+             atomicity = (System, Monotonic),
+             failureMemoryOrdering = Monotonic,
+             metadata = []
+           },
+           "cmpxchg i32* %2, i32 %0, i32 %0 monotonic monotonic"),
+          ("atomicrmw",
+           AtomicRMW {
+             volatile = False,
+             rmwOperation = RMWOp.UMax,
+             address = a 2,
+             value = a 0,
+             atomicity = (System, Release),
+             metadata = []
+           },
+           "atomicrmw umax i32* %2, i32 %0 release"),
+
+          ("trunc",
+           Trunc {
+             operand0 = a 0,
+             type' = i16,
+             metadata = []
+           },
+           "trunc i32 %0 to i16"),
+          ("zext",
+           ZExt {
+             operand0 = a 0,
+             type' = i64,
+             metadata = []
+           },
+           "zext i32 %0 to i64"),
+          ("sext",
+           SExt {
+             operand0 = a 0,
+             type' = i64,
+             metadata = []
+           },
+           "sext i32 %0 to i64"),
+          ("fptoui",
+           FPToUI {
+             operand0 = a 1,
+             type' = i64,
+             metadata = []
+           },
+           "fptoui float %1 to i64"),
+          ("fptosi",
+           FPToSI {
+             operand0 = a 1,
+             type' = i64,
+             metadata = []
+           },
+           "fptosi float %1 to i64"),
+          ("uitofp",
+           UIToFP {
+             operand0 = a 0,
+             type' = float,
+             metadata = []
+           },
+           "uitofp i32 %0 to float"),
+          ("sitofp",
+           SIToFP {
+             operand0 = a 0,
+             type' = float,
+             metadata = []
+           },
+           "sitofp i32 %0 to float"),
+          ("fptrunc",
+           FPTrunc {
+             operand0 = a 1,
+             type' = half,
+             metadata = []
+           },
+           "fptrunc float %1 to half"),
+          ("fpext",
+           FPExt {
+             operand0 = a 1,
+             type' = double,
+             metadata = []
+           },
+           "fpext float %1 to double"),
+          ("ptrtoint",
+           PtrToInt {
+             operand0 = a 2,
+             type' = i32,
+             metadata = []
+           },
+           "ptrtoint i32* %2 to i32"),
+          ("inttoptr",
+           IntToPtr {
+             operand0 = a 0,
+             type' = ptr i32,
+             metadata = []
+           },
+           "inttoptr i32 %0 to i32*"),
+          ("bitcast",
+           BitCast {
+             operand0 = a 0,
+             type' = float,
+             metadata = []
+           },
+           "bitcast i32 %0 to float"),
+          ("addrspacecast",
+           AddrSpaceCast {
+             operand0 = a 2,
+             type' = PointerType i32 (AddrSpace 2),
+             metadata = []
+           },
+           "addrspacecast i32* %2 to i32 addrspace(2)*"),
+          ("select",
+           Select {
+             condition' = a 4,
+             trueValue = a 0,
+             falseValue = a 0,
+             metadata = []
+           },
+           "select i1 %4, i32 %0, i32 %0"),
+          ("vaarg",
+           VAArg {
+             argList = a 2,
+             type' = i16,
+             metadata = []
+           },
+           "va_arg i32* %2, i16"),
+          ("extractelement",
+           ExtractElement {
+             vector = a 5,
+             index = a 0,
+             metadata = []
+           },
+           "extractelement <2 x i32> %5, i32 %0"),
+          ("insertelement",
+           InsertElement {
+             vector = a 5,
+             element = a 0,
+             index = a 0,
+             metadata = []
+           },
+           "insertelement <2 x i32> %5, i32 %0, i32 %0"),
+          ("shufflevector",
+           ShuffleVector {
+             operand0 = a 5,
+             operand1 = a 5,
+             mask = [0..1],
+             metadata = []
+           },
+           "shufflevector <2 x i32> %5, <2 x i32> %5, <2 x i32> <i32 0, i32 1>"),
+          ("extractvalue",
+           ExtractValue {
+             aggregate = a 6,
+             indices' = [0],
+             metadata = []
+           },
+           "extractvalue { i32, i32 } %6, 0"),
+          ("insertvalue",
+           InsertValue {
+             aggregate = a 6,
+             element = a 0,
+             indices' = [0],
+             metadata = []
+           },
+           "insertvalue { i32, i32 } %6, i32 %0, 0")
+         ] ++ [
+          ("landingpad-" ++ n,
+           LandingPad {
+             type' = StructureType False [
+                ptr i8,
+                i32
+               ],
+             cleanup = cp,
+             clauses = cls,
+             metadata = []
+           },
+           "landingpad { i8*, i32 }" <> s)
+          | (clsn,cls,clss) <- [
+           ("catch",
+            [Catch (C.Null (ptr i8))],
+            "\n          catch i8* null"),
+           ("filter",
+            [Filter (C.AggregateZero (ArrayType 1 (ptr i8)))],
+            "\n          filter [1 x i8*] zeroinitializer")
+          ],
+          (cpn, cp, cps) <- [ ("-cleanup", True, "\n          cleanup"), ("", False, "") ],
+          let s = cps <> clss
+              n = clsn <> cpn
+         ] ++ [
+          ("icmp-" ++ ByteString.unpack ps,
+           ICmp { iPredicate = p, operand0 = a 0, operand1 = a 0, metadata = [] },
+           "icmp " <> ps <> " i32 %0, %0")
+           | (ps, p) <- [
+           ("eq", IPred.EQ),
+           ("ne", IPred.NE),
+           ("ugt", IPred.UGT),
+           ("uge", IPred.UGE),
+           ("ult", IPred.ULT),
+           ("ule", IPred.ULE),
+           ("sgt", IPred.SGT),
+           ("sge", IPred.SGE),
+           ("slt", IPred.SLT),
+           ("sle", IPred.SLE)
+          ]
+         ] ++ [
+          ("fcmp-" ++ ByteString.unpack ps,
+           FCmp { fpPredicate = p, operand0 = a 1, operand1 = a 1, metadata = [] },
+           "fcmp " <> ps <> " float %1, %1")
+           | (ps, p) <- [
+           ("false", FPPred.False),
+           ("oeq", FPPred.OEQ),
+           ("ogt", FPPred.OGT),
+           ("oge", FPPred.OGE),
+           ("olt", FPPred.OLT),
+           ("ole", FPPred.OLE),
+           ("one", FPPred.ONE),
+           ("ord", FPPred.ORD),
+           ("uno", FPPred.UNO),
+           ("ueq", FPPred.UEQ),
+           ("ugt", FPPred.UGT),
+           ("uge", FPPred.UGE),
+           ("ult", FPPred.ULT),
+           ("ule", FPPred.ULE),
+           ("une", FPPred.UNE),
+           ("true", FPPred.True)
+          ]
+         ]
+        ] ++ [
+         ("store",
+          Do $ Store {
+            volatile = False,
+            address = a 2,
+            value = a 0,
+            maybeAtomicity = Nothing,
+            alignment = 4,
+            metadata = []
+          },
+          "store i32 %0, i32* %2, align 4"),
+         ("fence",
+          Do $ Fence {
+            atomicity = (System, Acquire),
+            metadata = []
+          },
+          "fence acquire"),
+          ("call",
+           Do $ Call {
+             tailCallKind = Nothing,
+             callingConvention = CC.C,
+             returnAttributes = [],
+             function = Right (ConstantOperand (C.GlobalReference (ptr (FunctionType A.T.void ts False)) (UnName 0))),
+             arguments = [ (a i, []) | i <- [0..6] ],
+             functionAttributes = [],
+             metadata = []
+           },
+           "call void @0(i32 %0, float %1, i32* %2, i64 %3, i1 %4, <2 x i32> %5, { i32, i32 } %6)")
+        ]
+      )
+   ],
+  testCase "GEP inBounds constant" $ do
+    let mAST = Module "<string>" "<string>" Nothing Nothing [
+          GlobalDefinition $ globalVariableDefaults {
+            G.name = Name "fortytwo",
+            G.type' = i32,
+            G.isConstant = True,
+            G.initializer = Just $ C.Int 32 42
+          },
+          GlobalDefinition $ functionDefaults {
+            G.returnType = i32,
+            G.name = UnName 0,
+            G.basicBlocks = [
+              BasicBlock (UnName 1) [
+                UnName 2 := GetElementPtr {
+                  inBounds = True,
+                  address = ConstantOperand (C.GlobalReference (ptr i32) (Name "fortytwo")),
+                  indices = [ ConstantOperand (C.Int 32 0) ],
+                  metadata = []
+                },
+                UnName 3 := Load {
+                  volatile = False,
+                  address = LocalReference (ptr i32) (UnName 2),
+                  maybeAtomicity = Nothing,
+                  alignment = 1,
+                  metadata = []
+                }
+              ] (
+                Do $ Ret (Just (LocalReference i32 (UnName 3))) []
+              )
+             ]
+           }
+          ]
+        mStr = "; ModuleID = '<string>'\n\
+               \source_filename = \"<string>\"\n\
+               \\n\
+               \@fortytwo = constant i32 42\n\
+               \\n\
+               \define i32 @0() {\n\
+               \  %1 = getelementptr inbounds i32, i32* @fortytwo, i32 0\n\
+               \  %2 = load i32, i32* %1, align 1\n\
+               \  ret i32 %2\n\
+               \}\n"
+    s <- withContext $ \context -> withModuleFromAST context mAST moduleLLVMAssembly
+    s @?= mStr,
+
+  testGroup "terminators" [
+    testCase name $ strCheck mAST mStr
+    | (name, mAST, mStr) <- [
+     (
+       "ret",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = UnName 0,
+          G.basicBlocks = [
+            BasicBlock (UnName 0) [
+             ] (
+              Do $ Ret Nothing []
+             )
+           ]
+         }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \  ret void\n\
+       \}\n"
+     ), (
+       "br",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = UnName 0,
+          G.basicBlocks = [
+            BasicBlock (UnName 0) [] (
+              Do $ Br (Name "foo") []
+             ),
+            BasicBlock (Name "foo") [] (
+              Do $ Ret Nothing []
+             )
+           ]
+         }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \  br label %foo\n\
+       \\n\
+       \foo:                                              ; preds = %0\n\
+       \  ret void\n\
+       \}\n"
+     ), (
+       "condbr",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = UnName 0,
+          G.basicBlocks = [
+            BasicBlock (Name "bar") [] (
+              Do $ CondBr (ConstantOperand (C.Int 1 1)) (Name "foo") (Name "bar") []
+             ),
+            BasicBlock (Name "foo") [] (
+              Do $ Ret Nothing []
+             )
+           ]
+          }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \bar:\n\
+       \  br i1 true, label %foo, label %bar\n\
+       \\n\
+       \foo:                                              ; preds = %bar\n\
+       \  ret void\n\
+       \}\n"
+     ), (
+       "switch",
+       Module "<string>" "<string>" Nothing Nothing [
+         GlobalDefinition $ functionDefaults {
+           G.returnType = A.T.void,
+           G.name = UnName 0,
+           G.basicBlocks = [
+             BasicBlock (UnName 0) [] (
+               Do $ Switch {
+                 operand0' = ConstantOperand (C.Int 16 2),
+                 defaultDest = Name "foo",
+                 dests = [
+                  (C.Int 16 0, UnName 0),
+                  (C.Int 16 2, Name "foo"),
+                  (C.Int 16 3, UnName 0)
+                 ],
+                 metadata' = []
+              }
+             ),
+             BasicBlock (Name "foo") [] (
+               Do $ Ret Nothing []
+              )
+            ]
+          }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \  switch i16 2, label %foo [\n\
+       \    i16 0, label %0\n\
+       \    i16 2, label %foo\n\
+       \    i16 3, label %0\n\
+       \  ]\n\
+       \\n\
+       \foo:                                              ; preds = %0, %0\n\
+       \  ret void\n\
+       \}\n"
+     ), (
+       "indirectbr",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ globalVariableDefaults {
+          G.name = UnName 0,
+          G.type' = ptr i8,
+          G.initializer = Just (C.BlockAddress (Name "foo") (UnName 2))
+        },
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = Name "foo",
+          G.basicBlocks = [
+            BasicBlock (UnName 0) [
+              UnName 1 := Load {
+                       volatile = False,
+                       address = ConstantOperand (C.GlobalReference (ptr (ptr i8)) (UnName 0)),
+                       maybeAtomicity = Nothing,
+                       alignment = 8,
+                       metadata = []
+                     }
+            ] (
+              Do $ IndirectBr {
+                operand0' = LocalReference (ptr i8) (UnName 1),
+                possibleDests = [UnName 2],
+                metadata' = []
+             }
+            ),
+            BasicBlock (UnName 2) [] (
+              Do $ Ret Nothing []
+             )
+           ]
+         }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \@0 = global i8* blockaddress(@foo, %2)\n\
+       \\n\
+       \define void @foo() {\n\
+       \  %1 = load i8*, i8** @0, align 8\n\
+       \  indirectbr i8* %1, [label %2]\n\
+       \\n\
+       \2:                                                ; preds = %0\n\
+       \  ret void\n\
+       \}\n"
+     ), (
+       "invoke",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = UnName 0,
+          G.personalityFunction = Just $ C.GlobalReference
+            (ptr (FunctionType A.T.void [i32,i16] False))
+            (UnName 0)
+          ,
+          G.parameters = ([
+            Parameter i32 (UnName 0) [],
+            Parameter i16 (UnName 1) []
+           ], False),
+          G.basicBlocks = [
+            BasicBlock (UnName 2) [] (
+              Do $ Invoke {
+               callingConvention' = CC.C,
+               returnAttributes' = [],
+               function' = Right (ConstantOperand (C.GlobalReference (ptr (FunctionType A.T.void [i32, i16] False)) (UnName 0))),
+               arguments' = [
+                (ConstantOperand (C.Int 32 4), []),
+                (ConstantOperand (C.Int 16 8), [])
+               ],
+               functionAttributes' = [],
+               returnDest = Name "foo",
+               exceptionDest = Name "bar",
+               metadata' = []
+              }
+             ),
+            BasicBlock (Name "foo") [] (
+              Do $ Ret Nothing []
+             ),
+            BasicBlock (Name "bar") [
+             UnName 3 := LandingPad {
+               type' = StructureType False [
+                  ptr i8,
+                  i32
+                 ],
+               cleanup = True,
+               clauses = [Catch (C.Null (ptr i8))],
+               metadata = []
+             }
+             ] (
+              Do $ Ret Nothing []
+             )
+           ]
+         }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0(i32 %0, i16 %1) personality void (i32, i16)* @0 {\n\
+       \  invoke void @0(i32 4, i16 8)\n\
+       \          to label %foo unwind label %bar\n\
+       \\n\
+       \foo:                                              ; preds = %2\n\
+       \  ret void\n\
+       \\n\
+       \bar:                                              ; preds = %2\n\
+       \  %3 = landingpad { i8*, i32 }\n\
+       \          cleanup\n\
+       \          catch i8* null\n\
+       \  ret void\n\
+       \}\n"
+      ), (
+       "resume",
+       Module "<string>" "<string>" Nothing Nothing [
+         GlobalDefinition $ functionDefaults {
+           G.returnType = A.T.void,
+           G.name = UnName 0,
+           G.basicBlocks = [
+             BasicBlock (UnName 0) [] (
+               Do $ Resume (ConstantOperand (C.Int 32 1)) []
+              )
+            ]
+          }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \  resume i32 1\n\
+       \}\n"
+     ), (
+       "unreachable",
+       Module "<string>" "<string>" Nothing Nothing [
+        GlobalDefinition $ functionDefaults {
+          G.returnType = A.T.void,
+          G.name = UnName 0,
+          G.basicBlocks = [
+            BasicBlock (UnName 0) [] (
+              Do $ Unreachable []
+             )
+           ]
+         }
+        ],
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \define void @0() {\n\
+       \  unreachable\n\
+       \}\n"
+     ), ( -- This testcase is taken from test/Feature/exception.ll in LLVM
+       "cleanupret0",
+       Module {
+         moduleName = "<string>",
+         moduleSourceFileName = "<string>",
+         moduleDataLayout = Nothing,
+         moduleTargetTriple = Nothing,
+         moduleDefinitions = [
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "_Z3quxv"
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = IntegerType {typeBits = 32},
+             G.name = Name "__gxx_personality_v0",
+             G.parameters = ([], True)
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "cleanupret0",
+             G.basicBlocks = [
+               G.BasicBlock (Name "entry") [] (
+                 Do Invoke {
+                   callingConvention' = CC.C,
+                   returnAttributes' = [],
+                   function' = Right (
+                     ConstantOperand (
+                       C.GlobalReference PointerType {
+                         pointerReferent = FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False},
+                         pointerAddrSpace = AddrSpace 0
+                       } (Name "_Z3quxv")
+                     )
+                   ),
+                   arguments' = [],
+                   returnDest = Name "exit",
+                   exceptionDest = Name "pad",
+                   metadata' = [],
+                   functionAttributes' = []
+                 }
+               ),
+               G.BasicBlock
+                 (Name "pad")
+                 [Name "cp" := CleanupPad { parentPad = ConstantOperand C.TokenNone, args = [ConstantOperand C.Int { C.integerBits = 7, C.integerValue = 4 }], metadata = [] }]
+                 (
+                 Do CleanupRet {
+                   cleanupPad = LocalReference TokenType (Name "cp"),
+                   unwindDest = Nothing,
+                   metadata' = []
+                 }
+                 ),
+               G.BasicBlock (Name "exit") [] (Do Ret { returnOperand = Nothing, metadata' = [] })
+             ],
+             G.personalityFunction = Just (
+               C.GlobalReference PointerType {
+                 pointerReferent = FunctionType {resultType = IntegerType { typeBits = 32 }, argumentTypes = [], isVarArg = True},
+                 pointerAddrSpace = AddrSpace 0
+               } (Name "__gxx_personality_v0")
+             )
+           }
+         ]
+       },
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \declare void @_Z3quxv()\n\
+       \\n\
+       \declare i32 @__gxx_personality_v0(...)\n\
+       \\n\
+       \define void @cleanupret0() personality i32 (...)* @__gxx_personality_v0 {\n\
+       \entry:\n\
+       \  invoke void @_Z3quxv()\n\
+       \          to label %exit unwind label %pad\n\
+       \\n\
+       \pad:                                              ; preds = %entry\n\
+       \  %cp = cleanuppad within none [i7 4]\n\
+       \  cleanupret from %cp unwind to caller\n\
+       \\n\
+       \exit:                                             ; preds = %entry\n\
+       \  ret void\n\
+       \}\n"
+     ), ( -- This testcase is taken from test/Feature/exception.ll in LLVM
+       "cleanupret1",
+       Module {
+         moduleName = "<string>",
+         moduleSourceFileName = "<string>",
+         moduleDataLayout = Nothing,
+         moduleTargetTriple = Nothing,
+         moduleDefinitions = [
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "_Z3quxv"
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = IntegerType {typeBits = 32},
+             G.name = Name "__gxx_personality_v0",
+             G.parameters = ([], True)
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "cleanupret1",
+             G.basicBlocks = [
+               G.BasicBlock (Name "entry") [] (
+                 Do Invoke {
+                   callingConvention' = CC.C,
+                   returnAttributes' = [],
+                   function' = Right (
+                     ConstantOperand (
+                       C.GlobalReference PointerType {
+                         pointerReferent = FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False},
+                         pointerAddrSpace = AddrSpace 0
+                       } (Name "_Z3quxv")
+                     )
+                   ),
+                   arguments' = [],
+                   returnDest = Name "exit",
+                   exceptionDest = Name "pad",
+                   metadata' = [],
+                   functionAttributes' = []
+                 }
+               ),
+               G.BasicBlock
+                 (Name "cleanup")
+                 []
+                 (Do CleanupRet {
+                    cleanupPad = LocalReference TokenType (Name "cp"),
+                    unwindDest = Nothing,
+                    metadata' = []
+                 }),
+               G.BasicBlock
+                 (Name "pad")
+                 [Name "cp" := CleanupPad { parentPad = ConstantOperand C.TokenNone, args = [], metadata = [] }]
+                 (Do Br { dest = Name "cleanup", metadata' = [] }),
+               G.BasicBlock (Name "exit") [] (Do Ret { returnOperand = Nothing, metadata' = [] })
+             ],
+             G.personalityFunction = Just (
+               C.GlobalReference PointerType {
+                 pointerReferent = FunctionType {resultType = IntegerType { typeBits = 32 }, argumentTypes = [], isVarArg = True},
+                 pointerAddrSpace = AddrSpace 0
+               } (Name "__gxx_personality_v0")
+             )
+           }
+         ]
+       },
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \declare void @_Z3quxv()\n\
+       \\n\
+       \declare i32 @__gxx_personality_v0(...)\n\
+       \\n\
+       \define void @cleanupret1() personality i32 (...)* @__gxx_personality_v0 {\n\
+       \entry:\n\
+       \  invoke void @_Z3quxv()\n\
+       \          to label %exit unwind label %pad\n\
+       \\n\
+       \cleanup:                                          ; preds = %pad\n\
+       \  cleanupret from %cp unwind to caller\n\
+       \\n\
+       \pad:                                              ; preds = %entry\n\
+       \  %cp = cleanuppad within none []\n\
+       \  br label %cleanup\n\
+       \\n\
+       \exit:                                             ; preds = %entry\n\
+       \  ret void\n\
+       \}\n"
+     ), ( -- This testcase is taken from test/Feature/exception.ll in LLVM
+       "catchret0",
+       Module {
+         moduleName = "<string>",
+         moduleSourceFileName = "<string>",
+         moduleDataLayout = Nothing,
+         moduleTargetTriple = Nothing,
+         moduleDefinitions = [
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "_Z3quxv"
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = IntegerType {typeBits = 32},
+             G.name = Name "__gxx_personality_v0",
+             G.parameters = ([], True)
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "catchret0",
+             G.basicBlocks = [
+               G.BasicBlock (Name "entry") [] (
+                 Do Invoke {
+                   callingConvention' = CC.C,
+                   returnAttributes' = [],
+                   function' = Right (
+                     ConstantOperand (
+                       C.GlobalReference PointerType {
+                         pointerReferent = FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False},
+                         pointerAddrSpace = AddrSpace 0
+                       } (Name "_Z3quxv")
+                     )
+                   ),
+                   arguments' = [],
+                   returnDest = Name "exit",
+                   exceptionDest = Name "pad",
+                   metadata' = [],
+                   functionAttributes' = []
+                 }
+               ),
+               G.BasicBlock (Name "pad") [] (
+                 Name "cs1" := CatchSwitch {
+                   parentPad' = ConstantOperand C.TokenNone,
+                   catchHandlers = (Name "catch" :| []),
+                   defaultUnwindDest = Nothing,
+                   metadata' = []
+                 }
+               ),
+               G.BasicBlock
+                 (Name "catch")
+                 [Name "cp" := CatchPad { catchSwitch = LocalReference TokenType (Name "cs1"), args = [ConstantOperand C.Int { C.integerBits = 7, C.integerValue = 4 }], metadata = [] }] (
+                 Do CatchRet {
+                   catchPad = LocalReference TokenType (Name "cp"),
+                   successor = Name "exit",
+                   metadata' = []
+                 }
+               ),
+               G.BasicBlock (Name "exit") [] (Do Ret { returnOperand = Nothing, metadata' = [] })
+             ],
+             G.personalityFunction = Just (
+               C.GlobalReference PointerType {
+                 pointerReferent = FunctionType {resultType = IntegerType { typeBits = 32 }, argumentTypes = [], isVarArg = True},
+                 pointerAddrSpace = AddrSpace 0
+               } (Name "__gxx_personality_v0")
+             )
+           }
+         ]
+       },
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \declare void @_Z3quxv()\n\
+       \\n\
+       \declare i32 @__gxx_personality_v0(...)\n\
+       \\n\
+       \define void @catchret0() personality i32 (...)* @__gxx_personality_v0 {\n\
+       \entry:\n\
+       \  invoke void @_Z3quxv()\n\
+       \          to label %exit unwind label %pad\n\
+       \\n\
+       \pad:                                              ; preds = %entry\n\
+       \  %cs1 = catchswitch within none [label %catch] unwind to caller\n\
+       \\n\
+       \catch:                                            ; preds = %pad\n\
+       \  %cp = catchpad within %cs1 [i7 4]\n\
+       \  catchret from %cp to label %exit\n\
+       \\n\
+       \exit:                                             ; preds = %catch, %entry\n\
+       \  ret void\n\
+       \}\n"
+     ), ( -- This testcase is taken from test/Feature/exception.ll in LLVM
+       "catchret1",
+       Module {
+         moduleName = "<string>",
+         moduleSourceFileName = "<string>",
+         moduleDataLayout = Nothing,
+         moduleTargetTriple = Nothing,
+         moduleDefinitions = [
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "_Z3quxv"
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = IntegerType {typeBits = 32},
+             G.name = Name "__gxx_personality_v0",
+             G.parameters = ([], True)
+           },
+           GlobalDefinition functionDefaults {
+             G.returnType = VoidType,
+             G.name = Name "catchret0",
+             G.basicBlocks = [
+               G.BasicBlock (Name "entry") [] (
+                 Do Invoke {
+                   callingConvention' = CC.C,
+                   returnAttributes' = [],
+                   function' = Right (
+                     ConstantOperand (
+                       C.GlobalReference PointerType {
+                         pointerReferent = FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False},
+                         pointerAddrSpace = AddrSpace 0
+                       } (Name "_Z3quxv")
+                     )
+                   ),
+                   arguments' = [],
+                   returnDest = Name "exit",
+                   exceptionDest = Name "pad",
+                   metadata' = [],
+                   functionAttributes' = []
+                 }
+               ),
+               G.BasicBlock (Name "catchret") [] (
+                 Do CatchRet {
+                    catchPad = LocalReference TokenType (Name "cp"),
+                    successor = Name "exit",
+                    metadata' = []
+                 }
+               ),
+               G.BasicBlock (Name "pad") [] (
+                 Name "cs1" := CatchSwitch {
+                   parentPad' = ConstantOperand C.TokenNone,
+                   catchHandlers = (Name "catch" :| []),
+                   defaultUnwindDest = Nothing,
+                   metadata' = []
+                 }
+               ),
+               G.BasicBlock
+                 (Name "catch")
+                 [Name "cp" := CatchPad { catchSwitch = LocalReference TokenType (Name "cs1"), args = [ConstantOperand C.Int { C.integerBits = 7, C.integerValue = 4 }], metadata = [] }] (
+                 Do Br { dest = (Name "catchret"), metadata' = [] }
+               ),
+               G.BasicBlock (Name "exit") [] (Do Ret { returnOperand = Nothing, metadata' = [] })
+             ],
+             G.personalityFunction = Just (
+               C.GlobalReference PointerType {
+                 pointerReferent = FunctionType {resultType = IntegerType { typeBits = 32 }, argumentTypes = [], isVarArg = True},
+                 pointerAddrSpace = AddrSpace 0
+               } (Name "__gxx_personality_v0")
+             )
+           }
+         ]
+       },
+       "; ModuleID = '<string>'\n\
+       \source_filename = \"<string>\"\n\
+       \\n\
+       \declare void @_Z3quxv()\n\
+       \\n\
+       \declare i32 @__gxx_personality_v0(...)\n\
+       \\n\
+       \define void @catchret0() personality i32 (...)* @__gxx_personality_v0 {\n\
+       \entry:\n\
+       \  invoke void @_Z3quxv()\n\
+       \          to label %exit unwind label %pad\n\
+       \\n\
+       \catchret:                                         ; preds = %catch\n\
+       \  catchret from %cp to label %exit\n\
+       \\n\
+       \pad:                                              ; preds = %entry\n\
+       \  %cs1 = catchswitch within none [label %catch] unwind to caller\n\
+       \\n\
+       \catch:                                            ; preds = %pad\n\
+       \  %cp = catchpad within %cs1 [i7 4]\n\
+       \  br label %catchret\n\
+       \\n\
+       \exit:                                             ; preds = %catchret, %entry\n\
+       \  ret void\n\
+       \}\n"
+     )
+    ]
+   ],
+
+  testGroup "fast-math flags" [
+    testProperty "roundtrip" $ \flags ->
+     ioProperty $ withContext $ \ctx -> do
+       encodedFlags <- encodeM flags :: IO FFI.FastMathFlags
+       decodedFlags <- decodeM encodedFlags :: IO FastMathFlags
+       pure (decodedFlags === flags)
+  ]
+ ]
+
+instance Arbitrary FastMathFlags where
+  arbitrary = oneof
+    [ pure noFastMathFlags
+    , FastMathFlags <$>
+       arbitrary <*>
+       arbitrary <*>
+       arbitrary <*>
+       arbitrary <*>
+       arbitrary <*>
+       arbitrary <*>
+       arbitrary
+    ]
diff --git a/test/LLVM/Test/Instrumentation.hs b/test/LLVM/Test/Instrumentation.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Instrumentation.hs
@@ -0,0 +1,184 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Instrumentation where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad.Trans.Except
+import Control.Monad.Except (catchError)
+import Control.Monad.IO.Class
+
+import Data.Functor hiding (void)
+import qualified Data.List as List
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import LLVM.Module
+import LLVM.Context
+import LLVM.PassManager
+import LLVM.Transforms
+import LLVM.Target
+
+import LLVM.AST as A
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import LLVM.AST.DataLayout
+import LLVM.Triple
+import qualified LLVM.AST.IntegerPredicate as IPred
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+
+instrument :: PassSetSpec -> A.Module -> IO A.Module
+instrument s m = withContext $ \context -> withModuleFromAST context m $ \mIn' -> do
+  withPassManager s $ \pm -> runPassManager pm mIn'
+  moduleAST mIn'
+
+ast = do
+ dl <- withHostTargetMachineDefault getTargetMachineDataLayout
+ triple <- liftIO getDefaultTargetTriple
+ return $ Module "<string>" "<string>" (Just dl) (Just triple) [
+  -- This function is needed for AddressSanitizerModule
+  GlobalDefinition $ functionDefaults {
+    G.returnType = void,
+    G.name = Name "asan.module_ctor",
+    G.basicBlocks = [BasicBlock (UnName 0) [] (Do (Ret Nothing []))]
+  },
+  GlobalDefinition $ functionDefaults {
+    G.returnType = i32,
+    G.name = Name "foo",
+    G.parameters = ([Parameter i128 (Name "x") []],False),
+    G.basicBlocks = [
+      BasicBlock (UnName 0) [] (Do $ Br (Name "checkDone") []),
+      BasicBlock (Name "checkDone") [
+        UnName 1 := Phi {
+         type' = i128,
+         incomingValues = [
+          (LocalReference i128 (Name "x"), UnName 0),
+          (LocalReference i128 (Name "x'"), Name "even"),
+          (LocalReference i128 (Name "x''"), Name "odd")
+         ],
+         metadata = []
+        },
+        Name "count" := Phi {
+         type' = i32,
+         incomingValues = [
+          (ConstantOperand (C.Int 32 1), UnName 0),
+          (LocalReference i32 (Name "count'"), Name "even"),
+          (LocalReference i32 (Name "count'"), Name "odd")
+         ],
+         metadata = []
+        },
+        Name "count'" := Add {
+         nsw = False,
+         nuw = False,
+         operand0 = LocalReference i32 (Name "count"),
+         operand1 = ConstantOperand (C.Int 32 1),
+         metadata = []
+        },
+        Name "is one" := ICmp {
+         iPredicate = IPred.EQ,
+         operand0 = LocalReference i128 (UnName 1),
+         operand1 = ConstantOperand (C.Int 128 1),
+         metadata = []
+        }
+      ] (
+        Do $ CondBr (LocalReference i1 (Name "is one")) (Name "done") (Name "checkOdd") []
+      ),
+      BasicBlock (Name "checkOdd") [
+        Name "is odd" := Trunc (LocalReference i128 (UnName 1)) i1 []
+      ] (
+       Do $ CondBr (LocalReference i1 (Name "is odd")) (Name "odd") (Name "even") []
+      ),
+      BasicBlock (Name "even") [
+        Name "x'" := UDiv True (LocalReference i128 (UnName 1)) (ConstantOperand (C.Int 128 2)) []
+      ] (
+        Do $ Br (Name "checkDone") []
+      ),
+      BasicBlock (Name "odd") [
+        UnName 2 := Mul False False (LocalReference i128 (UnName 1)) (ConstantOperand (C.Int 128 3)) [],
+        Name "x''" := Add False False (LocalReference i128 (UnName 2)) (ConstantOperand (C.Int 128 1)) []
+      ] (
+        Do $ Br (Name "checkDone") []
+      ),
+      BasicBlock (Name "done") [
+      ] (
+        Do $ Ret (Just (LocalReference i32 (Name "count'"))) []
+      )
+     ]
+   },
+  GlobalDefinition $ functionDefaults {
+    G.returnType = i32,
+    G.name = Name "main",
+    G.parameters = ([
+      Parameter i32 (Name "argc") [],
+      Parameter (ptr (ptr i8)) (Name "argv") []
+     ],False),
+    G.basicBlocks = [
+      BasicBlock (UnName 0) [
+        UnName 1 := Call {
+          tailCallKind = Nothing,
+          callingConvention = CC.C,
+          returnAttributes = [],
+          function = Right
+            (ConstantOperand
+              (C.GlobalReference
+                 (PointerType
+                    { pointerReferent = FunctionType i32 [i128] False
+                    , pointerAddrSpace = AddrSpace 0})
+                 (Name "foo"))),
+          arguments = [
+           (ConstantOperand (C.Int 128 9491828328), [])
+          ],
+          functionAttributes = [],
+          metadata = []
+        }
+      ] (
+        Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+      )
+     ]
+   }
+  ]
+
+isMemorySanitizerSupported :: IO Bool
+isMemorySanitizerSupported = do
+  triple <- getProcessTargetTriple
+  let ~(Right triple') = runExcept (parseTriple triple)
+  let os' = os triple'
+  return $ Set.member os' (Set.fromList [FreeBSD, NetBSD, Linux])
+
+instrumentationPasses :: [(TestName, Pass, IO Bool)]
+instrumentationPasses = [
+    ("GCOVProfiler", defaultGCOVProfiler, return True),
+    ("AddressSanitizer", defaultAddressSanitizer, return True),
+    ("AddressSanitizerModule", defaultAddressSanitizerModule, return True),
+    ("ThreadSanitizer", defaultThreadSanitizer, return True),
+    ("BoundsChecking", BoundsChecking, return True),
+    ("MemorySanitizer", defaultMemorySanitizer, isMemorySanitizerSupported)
+  ]
+
+tests =
+  testGroup "Instrumentation" [
+  testGroup "basic" [
+    testCase n $ do
+      shouldTest <- checkIfShouldTest
+      if not shouldTest
+        then return ()
+        else do
+          triple <- getProcessTargetTriple
+          withTargetLibraryInfo triple $ \tli -> do
+            dl <- withHostTargetMachineDefault getTargetMachineDataLayout
+            ast <- ast
+            ast' <- instrument (defaultPassSetSpec { transforms = [p], dataLayout = Just dl, targetLibraryInfo = Just tli }) ast
+            let names ast = [ n | GlobalDefinition d <- moduleDefinitions ast, Name n <- return (G.name d) ]
+            names ast' `List.intersect` names ast @?= names ast
+    |
+    (n, p, checkIfShouldTest) <- instrumentationPasses
+    ]
+  ]
diff --git a/test/LLVM/Test/Linking.hs b/test/LLVM/Test/Linking.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Linking.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Linking where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Monad.Trans.Except
+import Data.Functor
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import LLVM.Module
+import LLVM.Context
+import LLVM.PassManager
+import LLVM.Transforms
+import LLVM.Target
+
+import LLVM.AST as A
+import LLVM.AST.Type
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import LLVM.AST.DataLayout
+import qualified LLVM.AST.IntegerPredicate as IPred
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+
+tests = testGroup "Linking" [
+  testCase "basic" $ do
+    let 
+      ast0 = Module "<string>" "<string>" Nothing Nothing [
+          GlobalDefinition $ functionDefaults {
+             G.linkage = L.Private,
+             G.returnType = i32,
+             G.name = Name "private0"
+           },
+          GlobalDefinition $ functionDefaults {
+             G.linkage = L.External,
+             G.returnType = i32,
+             G.name = Name "external0"
+           }
+        ]
+      ast1 = Module "<string>" "<string>" Nothing Nothing [
+          GlobalDefinition $ functionDefaults {
+             G.linkage = L.Private,
+             G.returnType = i32,
+             G.name = Name "private1"
+           },
+          GlobalDefinition $ functionDefaults {
+             G.linkage = L.External,
+             G.returnType = i32,
+             G.name = Name "external1"
+           }
+        ]      
+
+    Module { moduleDefinitions = defs } <- withContext $ \context -> 
+      withModuleFromAST context ast0 $ \dest -> do
+      withModuleFromAST context ast0 $ \src -> do
+        linkModules dest src
+        moduleAST dest
+    [ n | GlobalDefinition g <- defs, let Name n = G.name g ] @?= [ "private0", "external0" ]
+ ]
diff --git a/test/LLVM/Test/Metadata.hs b/test/LLVM/Test/Metadata.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Metadata.hs
@@ -0,0 +1,1047 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module LLVM.Test.Metadata where
+
+import LLVM.Prelude
+
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.Tasty.QuickCheck
+import Test.QuickCheck as QC
+
+import LLVM.Test.Support
+
+import Control.Monad.IO.Class
+import Data.ByteString as B (readFile)
+import qualified Data.ByteString.Short as BSS
+import Data.Functor.Identity
+import Data.Maybe (catMaybes)
+import Foreign.Ptr
+import Text.Show.Pretty (pPrint)
+
+import qualified LLVM.AST.IntegerPredicate as IP
+import LLVM.AST as A hiding (GlobalVariable, PointerType)
+import LLVM.AST.Operand hiding (Module)
+import qualified LLVM.AST.Operand as O
+import qualified LLVM.AST.Operand as A (DIFlag(..), Virtuality(..), DIInheritance(..), DIAccessibility(..))
+import LLVM.AST.Type as A.T hiding (PointerType)
+import LLVM.AST.AddrSpace as A
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Constant as C
+import LLVM.AST.Global as G hiding (GlobalVariable)
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.Internal.Coding
+import LLVM.Internal.DecodeAST
+import LLVM.Internal.EncodeAST
+import qualified LLVM.Internal.FFI.PtrHierarchy as FFI
+import qualified LLVM.Internal.FFI.Metadata as FFI
+
+tests = testGroup "Metadata"
+  [ globalMetadata
+  , namedMetadata
+  , nullMetadata
+  , cyclicMetadata
+  , metadataConstantFolding
+  , globalObjectMetadata
+  , roundtripDIBasicType
+  , roundtripDIDerivedType
+  , roundtripDISubroutineType
+  , roundtripDIArrayType
+  , roundtripDIEnumerationType
+  , roundtripDIStructureType
+  , roundtripDIClassType
+  , roundtripDIUnionType
+  , roundtripDIFile
+  , roundtripDINode
+  , roundtripDICompileUnit
+  , roundtripDIVariable
+  , roundtripDIFlags
+  , roundtripDISubprogram
+  , roundtripDILexicalBlockBase
+  , roundtripDITemplateParameter
+  , roundtripDINamespace
+  , roundtripDIExpression
+  , diFlagName
+  , testFile
+  ]
+
+instance Arbitrary Encoding where
+  arbitrary =
+    QC.elements
+      [ AddressEncoding
+      , BooleanEncoding
+      , FloatEncoding
+      , SignedEncoding
+      , SignedCharEncoding
+      , UnsignedEncoding
+      , UnsignedCharEncoding
+      , UTFEncoding
+      ]
+
+instance Arbitrary ChecksumInfo where
+  arbitrary =
+    oneof
+      [ ChecksumInfo MD5 . BSS.pack <$> QC.vector 32
+      , ChecksumInfo SHA1 . BSS.pack <$> QC.vector 40
+      ]
+
+instance Arbitrary BasicTypeTag where
+  arbitrary = QC.elements [BaseType, UnspecifiedType]
+
+instance Arbitrary DIType where
+  arbitrary = oneof [DIBasicType <$> arbitrary]
+
+instance Arbitrary DIBasicType where
+  arbitrary = BasicType <$> arbitrarySbs <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> genDIFlags
+
+genDIArrayType :: Maybe (MDRef DIType) -> Gen DICompositeType
+genDIArrayType elTy =
+  DIArrayType <$> arbitrary <*> pure elTy <*> arbitrary <*> arbitrary <*> genDIFlags
+
+instance Arbitrary DIMacroInfo where
+  arbitrary = QC.elements [Define, Undef]
+
+genDIMacro :: Gen DIMacroNode
+genDIMacro =
+  DIMacro <$> arbitrary <*> arbitrary <*> arbitrarySbs <*> arbitrarySbs
+
+roundtripDIArrayType :: TestTree
+roundtripDIArrayType = testProperty "roundtrip DIArrayType" $ \elType ->
+  forAll (genDIArrayType (Just (MDRef elTyID))) $ \diArrayType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [arrayTypeID]
+                , MetadataNodeDefinition arrayTypeID (DINode (DIScope (DIType (DICompositeType diArrayType))))
+                , MetadataNodeDefinition elTyID (DINode (DIScope (DIType elType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where arrayTypeID = MetadataNodeID 0
+        elTyID = MetadataNodeID 1
+
+genDIEnumerationType :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> Maybe (MDRef DIType) -> Gen DICompositeType
+genDIEnumerationType scope file baseTy =
+  DIEnumerationType
+    <$> pure scope
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> arbitrary
+    <*> pure baseTy
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrary
+
+roundtripDIEnumerationType :: TestTree
+roundtripDIEnumerationType = testProperty "roundtrip DIEnumerationType" $ \file baseType ->
+  forAll (genDIEnumerationType Nothing (Just (MDRef fileID)) (Just (MDRef baseTyID))) $ \diEnumType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [enumTypeID]
+                , MetadataNodeDefinition enumTypeID (DINode (DIScope (DIType (DICompositeType diEnumType))))
+                , MetadataNodeDefinition fileID (DINode (DIScope (DIFile file)))
+                , MetadataNodeDefinition baseTyID (DINode (DIScope (DIType baseType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where enumTypeID = MetadataNodeID 0
+        fileID = MetadataNodeID 1
+        baseTyID = MetadataNodeID 2
+
+genDIStructureType :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> Maybe (MDRef DIType) -> [MDRef (Either DIDerivedType DISubprogram)] -> Maybe (MDRef DIType) -> Gen DICompositeType
+genDIStructureType scope file derivedFrom elements vtableHolder =
+  DIStructureType
+    <$> pure scope
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> genDIFlags
+    <*> pure derivedFrom
+    <*> pure elements
+    <*> arbitrary
+    <*> pure vtableHolder
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrary
+
+roundtripDIStructureType :: TestTree
+roundtripDIStructureType = testProperty "roundtrip DIStructureType" $
+  forAll (genDIStructureType Nothing Nothing Nothing [] Nothing) $ \diStructureType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [structureTypeID]
+                , MetadataNodeDefinition structureTypeID (DINode (DIScope (DIType (DICompositeType diStructureType))))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where structureTypeID = MetadataNodeID 0
+
+genDIClassType :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> Maybe (MDRef DIType) -> [MDRef (Either DIDerivedType DISubprogram)] -> Maybe (MDRef DIType) -> [DITemplateParameter] -> Gen DICompositeType
+genDIClassType scope file derivedFrom elements vtableHolder templateParams =
+  DIClassType
+    <$> pure scope
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> genDIFlags
+    <*> pure derivedFrom
+    <*> pure elements
+    <*> pure vtableHolder
+    <*> pure templateParams
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrary
+
+roundtripDIClassType :: TestTree
+roundtripDIClassType = testProperty "roundtrip DIClassType" $
+  forAll (genDIClassType Nothing Nothing Nothing [] Nothing []) $ \diClassType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [classTypeID]
+                , MetadataNodeDefinition classTypeID (DINode (DIScope (DIType (DICompositeType diClassType))))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where classTypeID = MetadataNodeID 0
+
+genDIUnionType :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> [MDRef (Either DIDerivedType DISubprogram)] -> Gen DICompositeType
+genDIUnionType scope file elements =
+  DIUnionType
+    <$> pure scope
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> genDIFlags
+    <*> pure elements
+    <*> arbitrary
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrary
+
+roundtripDIUnionType :: TestTree
+roundtripDIUnionType = testProperty "roundtrip DIUnionType" $
+  forAll (genDIUnionType Nothing Nothing []) $ \diUnionType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [unionTypeID]
+                , MetadataNodeDefinition unionTypeID (DINode (DIScope (DIType (DICompositeType diUnionType))))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where unionTypeID = MetadataNodeID 0
+
+instance Arbitrary DIFile where
+  arbitrary =
+    O.File <$> arbitrarySbs <*> arbitrarySbs <*> arbitrary
+
+instance Arbitrary DISubrange where
+  arbitrary = Subrange <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
+
+instance Arbitrary DICount where
+  -- TODO: Also generate non-trivial DICountVariable case.
+  arbitrary = DICountConstant <$> arbitrary
+
+instance Arbitrary DIBound where
+  -- TODO: Also generate non-trivial DIBoundVariable, DIBoundExpression cases.
+  arbitrary = DIBoundConstant <$> arbitrary
+
+instance Arbitrary DIEnumerator where
+  arbitrary = Enumerator <$> arbitrary <*> arbitrary <*> arbitrarySbs
+
+instance Arbitrary DINode where
+  arbitrary =
+    oneof
+      [ DISubrange <$> arbitrary
+      , DIEnumerator <$> arbitrary
+      -- TODO: Also generate non-trivial cases.
+      ]
+
+roundtripDIBasicType :: TestTree
+roundtripDIBasicType = testProperty "roundtrip DIBasicType" $ \diType -> ioProperty $
+  withContext $ \context -> runEncodeAST context $ do
+    encodedDIType <- encodeM (diType :: DIType)
+    decodedDIType <- liftIO (runDecodeAST (decodeM (encodedDIType :: Ptr FFI.DIType)))
+    pure (decodedDIType === diType)
+
+roundtripDIDerivedType :: TestTree
+roundtripDIDerivedType = testProperty "roundtrip DIDerivedType" $ \baseType ->
+  forAll (QC.elements [Nothing, Just (MDRef baseTypeID)]) $ \baseType' ->
+  forAll (genDIDerivedType Nothing Nothing baseType') $ \diDerivedType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [derivedTypeID]
+                , NamedMetadataDefinition "dummy2" [baseTypeID]
+                , MetadataNodeDefinition derivedTypeID (DINode (DIScope (DIType (DIDerivedType diDerivedType))))
+                , MetadataNodeDefinition baseTypeID (DINode (DIScope (DIType baseType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where derivedTypeID = MetadataNodeID 0
+        baseTypeID = MetadataNodeID 1
+
+instance Arbitrary DerivedTypeTag where
+  arbitrary =
+    QC.elements [ Typedef, PointerType, PtrToMemberType, ReferenceType, RValueReferenceType
+             , ConstType, VolatileType, RestrictType, AtomicType, Member, Inheritance, Friend
+             ]
+
+genDIDerivedType :: Maybe (MDRef DIFile) -> Maybe (MDRef DIScope) -> Maybe (MDRef DIType) -> Gen DIDerivedType
+genDIDerivedType file scope baseType =
+  DerivedType
+    <$> arbitrary
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> pure scope
+    <*> pure baseType
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> genDIFlags
+
+roundtripDISubroutineType :: TestTree
+roundtripDISubroutineType = testProperty "roundtrip DISubroutineType" $ \argType ->
+  forAll (genDISubroutineType [Nothing, Just (MDRef argTypeID)]) $ \diSubroutineType -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [subroutineTypeID]
+                , MetadataNodeDefinition subroutineTypeID (DINode (DIScope (DIType (DISubroutineType diSubroutineType))))
+                , MetadataNodeDefinition argTypeID (DINode (DIScope (DIType argType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where subroutineTypeID = MetadataNodeID 0
+        argTypeID = MetadataNodeID 1
+
+genDISubroutineType :: [Maybe (MDRef DIType)] -> Gen DISubroutineType
+genDISubroutineType types =
+  SubroutineType
+    <$> genDIFlags
+    <*> arbitrary
+    <*> pure types
+
+roundtripDIFile :: TestTree
+roundtripDIFile = testProperty "roundtrip DIFile" $ \diFile -> ioProperty $
+  withContext $ \context -> runEncodeAST context $ do
+    encodedDIFile <- encodeM (diFile :: DIFile)
+    decodedDIFile <- liftIO (runDecodeAST (decodeM (encodedDIFile :: Ptr FFI.DIFile)))
+    pure (decodedDIFile === diFile)
+
+roundtripDINode :: TestTree
+roundtripDINode = testProperty "roundtrip DINode" $ \diNode -> ioProperty $
+  withContext $ \context -> runEncodeAST context $ do
+    encodedDINode <- encodeM (diNode :: DINode)
+    decodedDINode :: Either String DINode <- liftIO (runDecodeAST (decodeM (encodedDINode :: Ptr FFI.DINode)))
+    pure (decodedDINode === (Right diNode))
+
+roundtripDICompileUnit :: TestTree
+roundtripDICompileUnit = testProperty "roundtrip DICompileUnit" $ \diFile retainedType ->
+  forAll genDIMacro $ \diMacro ->
+  forAll (genDICompileUnit (MDRef fileID) (MDRef retainedID) (MDRef macroID)) $ \diCompileUnit -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [cuID]
+                , NamedMetadataDefinition "dummyMacro" [macroID]
+                , NamedMetadataDefinition "dummyRetained" [retainedID]
+                , MetadataNodeDefinition cuID (DINode (DIScope (DICompileUnit diCompileUnit)))
+                , MetadataNodeDefinition macroID (DIMacroNode diMacro)
+                , MetadataNodeDefinition retainedID (DINode (DIScope (DIType retainedType)))
+                , MetadataNodeDefinition fileID (DINode (DIScope (DIFile diFile)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where cuID = MetadataNodeID 0
+        macroID = MetadataNodeID 1
+        retainedID = MetadataNodeID 2
+        fileID = MetadataNodeID 3
+
+genDICompileUnit :: MDRef DIFile -> MDRef (Either DIType DISubprogram) -> MDRef DIMacroNode -> Gen DICompileUnit
+genDICompileUnit file retained macro =
+  CompileUnit
+    <$> arbitrary
+    <*> pure file
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> arbitrarySbs
+    <*> arbitrary
+    <*> pure []
+    <*> listOf (pure retained)
+    <*> pure []
+    <*> pure []
+    <*> listOf (pure macro)
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+
+instance Arbitrary DebugEmissionKind where
+  arbitrary = QC.elements [NoDebug, FullDebug, LineTablesOnly]
+
+instance Arbitrary DebugNameTableKind where
+  arbitrary = QC.elements [NameTableKindDefault, NameTableKindGNU, NameTableKindNone]
+
+roundtripDIVariable :: TestTree
+roundtripDIVariable = testProperty "roundtrip DIVariable" $ \diFile diType ->
+  forAll (genDIVariable Nothing (Just (MDRef fileID)) (Just (MDRef typeID))) $ \diVariable -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [varID]
+                , MetadataNodeDefinition varID (DINode (DIVariable diVariable))
+                , MetadataNodeDefinition fileID (DINode (DIScope (DIFile diFile)))
+                , MetadataNodeDefinition typeID (DINode (DIScope (DIType diType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where varID = MetadataNodeID 0
+        fileID = MetadataNodeID 1
+        typeID = MetadataNodeID 2
+
+genDIVariable :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> Maybe (MDRef DIType) -> Gen DIVariable
+genDIVariable diScope diFile diType =
+  case diScope of
+    Nothing -> DIGlobalVariable <$> globalVar
+    Just scope -> oneof [DILocalVariable <$> localVar scope, DIGlobalVariable <$> globalVar]
+  where
+    localVar scope =
+      LocalVariable
+        <$> arbitrarySbs
+        <*> pure scope
+        <*> pure diFile
+        <*> arbitrary
+        <*> pure diType
+        <*> genDIFlags
+        <*> arbitrary
+        <*> arbitrary
+    globalVar =
+      GlobalVariable
+        <$> arbitrarySbs
+        <*> pure diScope
+        <*> pure diFile
+        <*> arbitrary
+        <*> pure diType
+        <*> arbitrarySbs
+        <*> arbitrary
+        <*> arbitrary
+        <*> pure Nothing
+        <*> pure []
+        <*> arbitrary
+
+instance Arbitrary A.DIInheritance where
+  arbitrary = QC.elements [A.SingleInheritance, A.MultipleInheritance, A.VirtualInheritance]
+
+instance Arbitrary A.DIAccessibility where
+  arbitrary = QC.elements [A.Public, A.Protected, A.Private]
+
+instance Arbitrary A.DIFlag where
+  arbitrary =
+    oneof
+      [ A.Accessibility <$> arbitrary
+      , A.InheritanceFlag <$> arbitrary
+      , QC.elements
+          [ A.FwdDecl
+          , A.AppleBlock
+          , A.VirtualFlag
+          , A.Artificial
+          , A.Explicit
+          , A.Prototyped
+          , A.ObjcClassComplete
+          , A.ObjectPointer
+          , A.Vector
+          , A.StaticMember
+          , A.LValueReference
+          , A.RValueReference
+          , A.IntroducedVirtual
+          , A.BitField
+          , A.NoReturn
+          , A.TypePassByValue
+          , A.TypePassByReference
+          , A.EnumClass
+          , A.Thunk
+          , A.NonTrivial
+          , A.BigEndian
+          , A.LittleEndian
+          , A.AllCallsDescribed
+          ]
+      ]
+
+roundtripDIFlags :: TestTree
+roundtripDIFlags =
+  testProperty "roundtrip DIFlags" $
+  forAll genDIFlags $ \diFlags ->
+    let Identity encodedFlags = encodeM diFlags
+        Identity decodedFlags = decodeM (encodedFlags :: FFI.DIFlags)
+    in decodedFlags === diFlags
+
+genDIFlags :: Gen [DIFlag]
+genDIFlags = do
+  accessibility <-
+    QC.elements [Nothing, Just A.Public, Just A.Protected, Just A.Private]
+  inheritance <-
+    QC.elements
+      [ Nothing
+      , Just A.SingleInheritance
+      , Just A.MultipleInheritance
+      , Just A.VirtualInheritance
+      ]
+  maybeFlags <- traverse (\f -> QC.elements [Nothing, Just f]) flags
+  pure
+    (catMaybes
+       ((A.Accessibility <$> accessibility) :
+        (A.InheritanceFlag <$> inheritance) : maybeFlags))
+  where
+    flags =
+      [ A.FwdDecl
+      , A.AppleBlock
+      , A.VirtualFlag
+      , A.Artificial
+      , A.Explicit
+      , A.Prototyped
+      , A.ObjcClassComplete
+      , A.ObjectPointer
+      , A.Vector
+      , A.StaticMember
+      , A.LValueReference
+      , A.RValueReference
+      , A.IntroducedVirtual
+      , A.BitField
+      , A.NoReturn
+      , A.TypePassByValue
+      , A.TypePassByReference
+      , A.EnumClass
+      , A.Thunk
+      , A.NonTrivial
+      , A.BigEndian
+      , A.LittleEndian
+      , A.AllCallsDescribed
+      ]
+
+roundtripDISubprogram :: TestTree
+roundtripDISubprogram = testProperty "roundtrip DISubprogram" $
+  forAll (genDISubprogram Nothing Nothing Nothing Nothing Nothing [] Nothing [] []) $ \diSubprogram -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [subprogramID]
+                , MetadataNodeDefinition subprogramID (DINode (DIScope (DILocalScope (DISubprogram diSubprogram))))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where subprogramID = MetadataNodeID 0
+
+genDISubprogram :: Maybe (MDRef DIScope) -> Maybe (MDRef DIFile) -> Maybe (MDRef DISubroutineType) ->
+                   Maybe (MDRef DIType) -> Maybe (MDRef DICompileUnit) -> [MDRef DITemplateParameter] ->
+                   Maybe (MDRef DISubprogram) ->
+                   [MDRef DILocalVariable] -> [MDRef DIType] -> Gen DISubprogram
+genDISubprogram scope file type' containingType unit templateParams decl vars thrownTypes =
+  Subprogram
+    <$> pure scope
+    <*> arbitrarySbs
+    <*> arbitrarySbs
+    <*> pure file
+    <*> arbitrary
+    <*> pure type'
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> pure containingType
+    <*> arbitrary
+    <*> arbitrary
+    <*> arbitrary
+    <*> genDIFlags
+    <*> arbitrary
+    <*> pure unit
+    <*> pure templateParams
+    <*> pure decl
+    <*> pure vars
+    <*> pure thrownTypes
+
+roundtripDILexicalBlockBase :: TestTree
+roundtripDILexicalBlockBase = testProperty "roundtrip DILexicalBlockBase" $ \diFile ->
+  forAll (genDISubprogram Nothing Nothing Nothing Nothing Nothing [] Nothing [] []) $ \diSubprogram ->
+  forAll (genDILexicalBlockBase (MDRef subprogramID) (Just (MDRef fileID))) $ \block -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [blockID]
+                , MetadataNodeDefinition blockID (DINode (DIScope (DILocalScope (DILexicalBlockBase block))))
+                , MetadataNodeDefinition subprogramID (DINode (DIScope (DILocalScope (DISubprogram diSubprogram))))
+                , MetadataNodeDefinition fileID (DINode (DIScope (DIFile diFile)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where blockID = MetadataNodeID 0
+        subprogramID = MetadataNodeID 1
+        fileID = MetadataNodeID 2
+
+genDILexicalBlockBase :: MDRef DILocalScope -> Maybe (MDRef DIFile) -> Gen DILexicalBlockBase
+genDILexicalBlockBase scope file =
+  oneof
+    [ DILexicalBlock scope file <$> arbitrary <*> arbitrary
+    , DILexicalBlockFile scope file <$> arbitrary
+    ]
+
+instance Arbitrary Virtuality where
+  arbitrary = QC.elements [A.NoVirtuality, A.Virtual, A.PureVirtual]
+
+roundtripDITemplateParameter :: TestTree
+roundtripDITemplateParameter = testProperty "roundtrip DITemplateParameter" $ \diType ->
+  forAll (genDITemplateParameter (MDValue (ConstantOperand (C.Int 32 1))) (MDRef tyID)) $ \param -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [paramID]
+                , NamedMetadataDefinition "dummyTy" [tyID]
+                , MetadataNodeDefinition paramID (DINode (DITemplateParameter param))
+                , MetadataNodeDefinition tyID (DINode (DIScope (DIType diType)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where paramID = MetadataNodeID 0
+        tyID = MetadataNodeID 1
+
+instance Arbitrary TemplateValueParameterTag where
+  arbitrary = QC.elements [TemplateValueParameter, GNUTemplateTemplateParam, GNUTemplateParameterPack]
+
+genDITemplateParameter :: Metadata -> MDRef DIType -> Gen DITemplateParameter
+genDITemplateParameter value ty =
+  oneof [ DITemplateTypeParameter <$> arbitrarySbs <*> pure (Just ty)
+        , DITemplateValueParameter <$> arbitrarySbs <*> pure Nothing <*> pure (Just value) <*> arbitrary
+        ]
+
+roundtripDINamespace :: TestTree
+roundtripDINamespace = testProperty "roundtrip DINamespace" $ \diFile ->
+  forAll (genDINamespace (MDRef fileID)) $ \diNamespace -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      let mod = defaultModule
+            { moduleDefinitions =
+                [ NamedMetadataDefinition "dummy" [namespaceID]
+                , NamedMetadataDefinition "dummy2" [fileID]
+                , MetadataNodeDefinition namespaceID (DINode (DIScope (DINamespace diNamespace)))
+                , MetadataNodeDefinition fileID (DINode (DIScope (DIFile diFile)))
+                ]
+            }
+      mod' <- liftIO (withModuleFromAST context mod moduleAST)
+      pure (mod' === mod)
+  where namespaceID = MetadataNodeID 0
+        fileID = MetadataNodeID 1
+
+genDINamespace :: MDRef DIScope -> Gen DINamespace
+genDINamespace scope = Namespace <$> arbitrarySbs <*> QC.elements [Nothing, Just scope] <*> arbitrary
+
+diFlagName :: TestTree
+diFlagName =
+  testProperty "LLVM and llvm-hs agree on encoding of DIFlag" $ \diFlag ->
+    ioProperty $
+    withContext $ \context ->
+      runEncodeAST context $ do
+        encoded <- encodeM [diFlag]
+        flagName' <- encodeM ("DIFlag" <> flagName diFlag)
+        encodedByName <- liftIO (FFI.getDIFlag flagName')
+        pure (encoded === encodedByName)
+  where
+    flagName (A.Accessibility f) = show f
+    flagName (A.InheritanceFlag f) = show f
+    flagName A.VirtualFlag = "Virtual"
+    flagName f = show f
+
+roundtripDIExpression :: TestTree
+roundtripDIExpression = testProperty "roundtrip DIExpression" $
+  forAll genDIExpression $ \expr -> ioProperty $
+    withContext $ \context -> runEncodeAST context $ do
+      encodedExpr <- encodeM expr
+      decodedExpr <- liftIO (runDecodeAST (decodeM (encodedExpr :: Ptr FFI.DIExpression)))
+      pure (decodedExpr === expr)
+
+genDIExpression :: Gen DIExpression
+genDIExpression = Expression <$> arbitrary
+
+instance Arbitrary DWOp where
+  arbitrary =
+    oneof
+      [ DwOpFragment <$> (DW_OP_LLVM_Fragment <$> arbitrary <*> arbitrary)
+      , pure DW_OP_StackValue
+      , pure DW_OP_Swap
+      , pure DW_OP_Lit0
+      , DW_OP_ConstU <$> arbitrary
+      , DW_OP_PlusUConst <$> arbitrary
+      , pure DW_OP_Plus
+      , pure DW_OP_Minus
+      , pure DW_OP_Mul
+      , pure DW_OP_Div
+      , pure DW_OP_Mod
+      , pure DW_OP_Not
+      , pure DW_OP_Or
+      , pure DW_OP_Xor
+      , pure DW_OP_And
+      , pure DW_OP_Shr
+      , pure DW_OP_Shra
+      , pure DW_OP_Shl
+      , pure DW_OP_Dup
+      , pure DW_OP_Deref
+      , pure DW_OP_XDeref
+      ]
+
+testFile :: TestTree
+testFile = do
+  testGroup "file parsing and decoding"
+    [ testCase "test/debug_metadata_1.ll" $ do
+        fStr <- B.readFile "test/debug_metadata_1.ll"
+        withContext $ \context -> do
+          a <- withModuleFromLLVMAssembly' context fStr moduleAST
+          pure ()
+    ,  testCase "test/debug_metadata_2.ll" $ do
+         fStr <- B.readFile "test/debug_metadata_2.ll"
+         withContext $ \context -> do
+           a <- withModuleFromLLVMAssembly' context fStr moduleAST
+           pure ()
+    ,  testCase "test/debug_metadata_3.ll" $ do
+         fStr <- B.readFile "test/debug_metadata_3.ll"
+         withContext $ \context -> do
+           a <- withModuleFromLLVMAssembly' context fStr moduleAST
+           pure ()
+    ,  testCase "test/debug_metadata_4.ll" $ do
+         fStr <- B.readFile "test/debug_metadata_4.ll"
+         withContext $ \context -> do
+           a <- withModuleFromLLVMAssembly' context fStr moduleAST
+           pure ()
+    ,  testCase "test/debug_metadata_5.ll" $ do
+         fStr <- B.readFile "test/debug_metadata_5.ll"
+         withContext $ \context -> do
+           a <- withModuleFromLLVMAssembly' context fStr moduleAST
+           pure ()
+    ]
+
+globalMetadata = testCase "global" $ do
+    let ast = Module "<string>" "<string>" Nothing Nothing [
+          GlobalDefinition $ functionDefaults {
+            G.returnType = i32,
+            G.name = Name "foo",
+            G.basicBlocks = [
+              BasicBlock (UnName 0) [
+              ] (
+                Do $ Ret (Just (ConstantOperand (C.Int 32 0))) [
+                  ("my-metadatum", A.MDRef (MetadataNodeID 0))
+                ]
+              )
+             ]
+            },
+          MetadataNodeDefinition (MetadataNodeID 0) (MDTuple [ Just $ MDValue $ ConstantOperand (C.Int 32 1) ])
+         ]
+    let s = "; ModuleID = '<string>'\n\
+            \source_filename = \"<string>\"\n\
+            \\n\
+            \define i32 @foo() {\n\
+            \  ret i32 0, !my-metadatum !0\n\
+            \}\n\
+            \\n\
+            \!0 = !{i32 1}\n"
+    strCheck ast s
+
+namedMetadata = testCase "named" $ do
+    let ast = Module "<string>" "<string>" Nothing Nothing [
+          NamedMetadataDefinition "my-module-metadata" [ MetadataNodeID 0 ],
+          MetadataNodeDefinition (MetadataNodeID 0) (MDTuple [ Just $ MDValue $ ConstantOperand (C.Int 32 1) ])
+         ]
+    let s = "; ModuleID = '<string>'\n\
+            \source_filename = \"<string>\"\n\
+            \\n\
+            \!my-module-metadata = !{!0}\n\
+            \\n\
+            \!0 = !{i32 1}\n"
+    strCheck ast s
+
+nullMetadata = testCase "null" $ do
+    let ast = Module "<string>" "<string>" Nothing Nothing [
+          NamedMetadataDefinition "my-module-metadata" [ MetadataNodeID 0 ],
+          MetadataNodeDefinition (MetadataNodeID 0) (MDTuple [ Nothing ])
+         ]
+    let s = "; ModuleID = '<string>'\n\
+            \source_filename = \"<string>\"\n\
+            \\n\
+            \!my-module-metadata = !{!0}\n\
+            \\n\
+            \!0 = !{null}\n"
+    strCheck ast s
+
+cyclicMetadata = testGroup "cyclic" [
+    testCase "metadata-only" $ do
+      let ast = Module "<string>" "<string>" Nothing Nothing [
+            NamedMetadataDefinition "my-module-metadata" [MetadataNodeID 0],
+            MetadataNodeDefinition
+              (MetadataNodeID 0)
+              (MDTuple [Just $ MDNode (MDRef (MetadataNodeID 1))]),
+            MetadataNodeDefinition
+              (MetadataNodeID 1)
+              (MDTuple [Just $ MDNode (MDRef (MetadataNodeID 0))])
+           ]
+      let s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \!my-module-metadata = !{!0}\n\
+              \\n\
+              \!0 = !{!1}\n\
+              \!1 = !{!0}\n"
+      strCheck ast s,
+
+    testCase "metadata-global" $ do
+      let ast = Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+              G.returnType = A.T.void,
+              G.name = Name "foo",
+              G.basicBlocks = [
+                BasicBlock (UnName 0) [
+                 ] (
+                   Do $ Ret Nothing [ ("my-metadatum", MDRef (MetadataNodeID 0)) ]
+                 )
+               ]
+             },
+            MetadataNodeDefinition
+              (MetadataNodeID 0)
+              (MDTuple [Just $ MDValue $ ConstantOperand (C.GlobalReference (ptr (FunctionType A.T.void [] False)) (Name "foo"))])
+           ]
+      let s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \define void @foo() {\n\
+              \  ret void, !my-metadatum !0\n\
+              \}\n\
+              \\n\
+              \!0 = !{void ()* @foo}\n"
+      strCheck ast s
+   ]
+
+metadataConstantFolding = testGroup "constant folding" [
+    testCase "metadata on instructions that can be constant folded" $
+      let ast = Module "<string>" "<string>" Nothing Nothing
+            [ GlobalDefinition functionDefaults
+                { name = "f"
+                , parameters = ([Parameter i32 "x" []] , False)
+                , returnType = i32
+                , basicBlocks =
+                    [ BasicBlock "if"
+                        [UnName 0 := ICmp IP.EQ (ConstantOperand (C.Int 32 0)) (ConstantOperand (C.Int 32 0))
+                           [("foobar", MDRef (MetadataNodeID 0))]
+                        ]
+                        (Do (CondBr (LocalReference i1 (UnName 0)) "if.true" "if.false" []))
+                    , BasicBlock "if.true" []
+                        (Do (Ret (Just (ConstantOperand (C.Int 32 0))) []))
+                    , BasicBlock "if.false" []
+                        (Do (Ret (Just (ConstantOperand (C.Int 32 0))) []))
+                    ]
+                }
+            , MetadataNodeDefinition (MetadataNodeID 0) (MDTuple [])
+            ]
+          s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \define i32 @f(i32 %x) {\n\
+              \if:\n\
+              \  %0 = icmp eq i32 0, 0, !foobar !0\n\
+              \  br i1 %0, label %if.true, label %if.false\n\
+              \\n\
+              \if.true:                                          ; preds = %if\n\
+              \  ret i32 0\n\
+              \\n\
+              \if.false:                                         ; preds = %if\n\
+              \  ret i32 0\n\
+              \}\n\
+              \\n\
+              \!0 = !{}\n"
+      in strCheck ast s
+    ]
+
+globalObjectMetadata = testGroup "Metadata on GlobalObject" $
+  [ testCase "metadata on functions" $ do
+      let ast = Module "<string>" "<string>" Nothing Nothing
+                  [ GlobalDefinition
+                      functionDefaults
+                        { G.name = "main"
+                        , G.returnType = A.T.void
+                        , basicBlocks = [ BasicBlock (UnName 0) [] (Do (Ret Nothing [])) ]
+                        , G.metadata = [("dbg", MDRef (MetadataNodeID 0))]
+                        }
+                  , NamedMetadataDefinition "llvm.module.flags" [MetadataNodeID 1]
+                  , NamedMetadataDefinition "llvm.dbg.cu" [MetadataNodeID 2]
+                  , MetadataNodeDefinition (MetadataNodeID 0) $
+                    DINode .DIScope .DILocalScope . DISubprogram $
+                    Subprogram
+                      { scope = Nothing
+                      , name = "main"
+                      , linkageName = ""
+                      , file = Nothing
+                      , line = 0
+                      , type' = Nothing
+                      , localToUnit = False
+                      , definition = True
+                      , scopeLine = 0
+                      , containingType = Nothing
+                      , virtuality = NoVirtuality
+                      , virtualityIndex = 0
+                      , thisAdjustment = 0
+                      , flags = []
+                      , optimized = False
+                      , unit = Just (MDRef (MetadataNodeID 2))
+                      , O.templateParams = []
+                      , declaration = Nothing
+                      , retainedNodes = []
+                      , thrownTypes = []
+                      }
+                  , MetadataNodeDefinition (MetadataNodeID 1)
+                    (MDTuple [ Just (MDValue (ConstantOperand (C.Int 32 2)))
+                             , Just (MDString "Debug Info Version")
+                             , Just (MDValue (ConstantOperand (C.Int 32 3)))
+                             ])
+                  , MetadataNodeDefinition (MetadataNodeID 2) $
+                    DINode . DIScope . DICompileUnit $
+                    CompileUnit
+                      { language = 12
+                      , file = MDRef (MetadataNodeID 3)
+                      , producer = "clang version 6.0.0 (tags/RELEASE_600/final)"
+                      , optimized = True
+                      , flags = ""
+                      , runtimeVersion = 0
+                      , splitDebugFileName = ""
+                      , emissionKind = FullDebug
+                      , enums = []
+                      , retainedTypes = []
+                      , globals = []
+                      , imports = []
+                      , macros = []
+                      , dWOId = 0
+                      , splitDebugInlining = True
+                      , debugInfoForProfiling = False
+                      , nameTableKind = NameTableKindDefault
+                      , rangesBaseAddress = False
+                      }
+                  , MetadataNodeDefinition (MetadataNodeID 3) $
+                    DINode . DIScope . DIFile $
+                    O.File "main.c" "/" Nothing
+                  ]
+          s =
+            "; ModuleID = '<string>'\n\
+            \source_filename = \"<string>\"\n\
+            \\n\
+            \define void @main() !dbg !3 {\n\
+            \  ret void\n\
+            \}\n\
+            \\n\
+            \!llvm.module.flags = !{!0}\n\
+            \!llvm.dbg.cu = !{!1}\n\
+            \\n\
+            \!0 = !{i32 2, !\"Debug Info Version\", i32 3}\n\
+            \!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: \"clang version 6.0.0 (tags/RELEASE_600/final)\", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)\n\
+            \!2 = !DIFile(filename: \"main.c\", directory: \"/\")\n\
+            \!3 = distinct !DISubprogram(name: \"main\", scope: null, spFlags: DISPFlagDefinition, unit: !1)\n"
+      strCheck ast s,
+   testCase "metadata on global variables" $ do
+      let ast = Module "<string>" "<string>" Nothing Nothing
+                  [ GlobalDefinition
+                      globalVariableDefaults
+                        { G.name = "g"
+                        , G.type' = A.T.i32
+                        , G.linkage = L.Common
+                        , G.alignment = 4
+                        , G.initializer = Just (C.Int 32 0)
+                        , G.metadata = [("dbg", MDRef (MetadataNodeID 0))]
+                        }
+                  , NamedMetadataDefinition "llvm.module.flags" [MetadataNodeID 1]
+                  , NamedMetadataDefinition "llvm.dbg.cu" [MetadataNodeID 2]
+                  , MetadataNodeDefinition (MetadataNodeID 0) $
+                    DIGlobalVariableExpression $ GlobalVariableExpression (MDRef (MetadataNodeID 3)) (MDRef (MetadataNodeID 4))
+                  , MetadataNodeDefinition (MetadataNodeID 1)
+                    (MDTuple [ Just (MDValue (ConstantOperand (C.Int 32 2)))
+                             , Just (MDString "Debug Info Version")
+                             , Just (MDValue (ConstantOperand (C.Int 32 3)))
+                             ])
+                  , MetadataNodeDefinition (MetadataNodeID 2) $
+                    DINode . DIScope . DICompileUnit $
+                    CompileUnit
+                      { language = 12
+                      , file = MDRef (MetadataNodeID 5)
+                      , producer = "clang version 6.0.0 (tags/RELEASE_600/final)"
+                      , optimized = True
+                      , flags = ""
+                      , runtimeVersion = 0
+                      , splitDebugFileName = ""
+                      , emissionKind = FullDebug
+                      , enums = []
+                      , retainedTypes = []
+                      , globals = []
+                      , imports = []
+                      , macros = []
+                      , dWOId = 0
+                      , splitDebugInlining = True
+                      , debugInfoForProfiling = False
+                      , nameTableKind = NameTableKindDefault
+                      , rangesBaseAddress = False
+                      }
+                  , MetadataNodeDefinition (MetadataNodeID 3) $
+                    DINode . DIVariable . DIGlobalVariable $
+                    GlobalVariable
+                      { name = "g"
+                      , scope = Nothing
+                      , file = Nothing
+                      , line = 0
+                      , type' = Just (MDRef (MetadataNodeID 6))
+                      , linkageName = ""
+                      , local = False
+                      , definition = True
+                      , staticDataMemberDeclaration = Nothing
+                      , templateParams = []
+                      , alignInBits = 0
+                      }
+                  , MetadataNodeDefinition (MetadataNodeID 4) (DIExpression (Expression []))
+                  , MetadataNodeDefinition (MetadataNodeID 5) $
+                    DINode . DIScope . DIFile $
+                    O.File "main.c" "/" Nothing
+                  , MetadataNodeDefinition (MetadataNodeID 6) $
+                    DINode . DIScope . DIType . DIBasicType $
+                    BasicType "" 0 0 Nothing BaseType []
+                  ]
+          s =
+            "; ModuleID = '<string>'\n\
+            \source_filename = \"<string>\"\n\
+            \\n\
+            \@g = common global i32 0, align 4, !dbg !0\n\
+            \\n\
+            \!llvm.module.flags = !{!3}\n\
+            \!llvm.dbg.cu = !{!4}\n\
+            \\n\
+            \!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())\n\
+            \!1 = !DIGlobalVariable(name: \"g\", scope: null, type: !2, isLocal: false, isDefinition: true)\n\
+            \!2 = !DIBasicType()\n\
+            \!3 = !{i32 2, !\"Debug Info Version\", i32 3}\n\
+            \!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !5, producer: \"clang version 6.0.0 (tags/RELEASE_600/final)\", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)\n\
+            \!5 = !DIFile(filename: \"main.c\", directory: \"/\")\n"
+      strCheck ast s
+  ]
diff --git a/test/LLVM/Test/Module.hs b/test/LLVM/Test/Module.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Module.hs
@@ -0,0 +1,643 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Module where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Control.Exception
+import Control.Monad.Trans.Except
+import Data.Bits
+import Data.Word
+
+import qualified Data.Map as Map
+
+import LLVM.Context
+import LLVM.Exception
+import LLVM.Module
+import LLVM.Analysis
+import LLVM.Diagnostic
+import LLVM.Target
+import LLVM.AST
+import LLVM.AST.Type as T
+import LLVM.AST.AddrSpace
+import qualified LLVM.AST.IntegerPredicate as IPred
+
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.DLL as DLL
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.FunctionAttribute as FA
+import qualified LLVM.AST.ParameterAttribute as PA
+import qualified LLVM.AST.ThreadLocalStorage as TLS
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+import qualified LLVM.AST.COMDAT as COMDAT
+
+import qualified LLVM.Relocation as R
+import qualified LLVM.CodeModel as CM
+import qualified LLVM.CodeGenOpt as CGO
+
+handString = "; ModuleID = '<string>'\n\
+    \source_filename = \"<string>\"\n\
+    \\n\
+    \%0 = type { i32, %1*, %0* }\n\
+    \%1 = type opaque\n\
+    \\n\
+    \$bob = comdat largest\n\
+    \\n\
+    \@0 = global i32 1\n\
+    \@1 = external protected addrspace(3) global i32, section \"foo\", comdat($bob)\n\
+    \@2 = unnamed_addr global i8 2\n\
+    \@3 = external dllimport global %0\n\
+    \@4 = external global [4294967296 x i32]\n\
+    \@.argyle = thread_local global i32 0\n\
+    \@5 = thread_local(localdynamic) global i32 1\n\
+    \\n\
+    \@three = private alias i32, i32 addrspace(3)* @1\n\
+    \@two = unnamed_addr alias i32, i32 addrspace(3)* @three\n\
+    \@one = thread_local(initialexec) alias i32, i32* @5\n\
+    \\n\
+    \define i32 @bar() prefix i32 1 {\n\
+    \  %1 = musttail call zeroext i32 @foo(i32 inreg align 16 1, i8 signext 4) #0\n\
+    \  ret i32 %1\n\
+    \}\n\
+    \\n\
+    \define i32 @baz() prefix i32 1 {\n\
+    \  %1 = notail call zeroext i32 @foo(i32 inreg align 16 1, i8 signext 4) #0\n\
+    \  ret i32 %1\n\
+    \}\n\
+    \\n\
+    \; Function Attrs: nounwind readnone uwtable\n\
+    \define zeroext i32 @foo(i32 inreg align 16 %x, i8 signext %y) #0 {\n\
+    \  %1 = mul nsw i32 %x, %x\n\
+    \  br label %here\n\
+    \\n\
+    \here:                                             ; preds = %0\n\
+    \  %go = icmp eq i32 %1, %x\n\
+    \  br i1 %go, label %there, label %elsewhere\n\
+    \\n\
+    \there:                                            ; preds = %here\n\
+    \  %2 = add nsw i32 %1, 3\n\
+    \  br label %elsewhere\n\
+    \\n\
+    \elsewhere:                                        ; preds = %there, %here\n\
+    \  %r = phi i32 [ 2, %there ], [ 57, %here ]\n\
+    \  ret i32 %r\n\
+    \}\n\
+    \\n\
+    \attributes #0 = { nounwind readnone uwtable \"eep\" }\n"
+
+handAST = Module "<string>" "<string>" Nothing Nothing [
+      TypeDefinition (UnName 0) (
+         Just $ StructureType False [
+           i32,
+           ptr (NamedTypeReference (UnName 1)),
+           ptr (NamedTypeReference (UnName 0))
+          ]),
+      TypeDefinition (UnName 1) Nothing,
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 0,
+        G.type' = i32,
+        G.initializer = Just (C.Int 32 1)
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 1,
+        G.visibility = V.Protected,
+        G.type' = i32,
+        G.addrSpace = AddrSpace 3,
+        G.section = Just "foo",
+        G.comdat = Just "bob"
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 2,
+        G.unnamedAddr = Just GlobalAddr,
+        G.type' = i8,
+        G.initializer = Just (C.Int 8 2)
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 3,
+        G.dllStorageClass = Just DLL.Import,
+        G.type' = NamedTypeReference (UnName 0)
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 4,
+        G.type' = ArrayType (1 `shift` 32) i32
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = Name ".argyle",
+        G.type' = i32,
+        G.initializer = Just (C.Int 32 0),
+        G.threadLocalMode = Just TLS.GeneralDynamic
+      },
+      GlobalDefinition $ globalVariableDefaults {
+        G.name = UnName 5,
+        G.type' = i32,
+        G.threadLocalMode = Just TLS.LocalDynamic,
+        G.initializer = Just (C.Int 32 1)
+      },
+      GlobalDefinition $ globalAliasDefaults {
+         G.name = Name "three",
+         G.linkage = L.Private,
+         G.type' = i32,
+         G.addrSpace = AddrSpace 3,
+         G.aliasee = C.GlobalReference (PointerType i32 (AddrSpace 3)) (UnName 1)
+      },
+      GlobalDefinition $ globalAliasDefaults {
+        G.name = Name "two",
+        G.unnamedAddr = Just GlobalAddr,
+        G.type' = i32,
+        G.addrSpace = AddrSpace 3,
+        G.aliasee = C.GlobalReference (PointerType i32 (AddrSpace 3)) (Name "three")
+      },
+      GlobalDefinition $ globalAliasDefaults {
+        G.name = Name "one",
+        G.type' = i32,
+        G.aliasee = C.GlobalReference (ptr i32) (UnName 5),
+        G.threadLocalMode = Just TLS.InitialExec
+      },
+      GlobalDefinition $ functionDefaults {
+        G.returnType = i32,
+        G.name = Name "bar",
+        G.prefix = Just (C.Int 32 1),
+        G.basicBlocks = [
+          BasicBlock (UnName 0) [
+           UnName 1 := Call {
+             tailCallKind = Just MustTail,
+             callingConvention = CC.C,
+             returnAttributes = [PA.ZeroExt],
+             function = Right (ConstantOperand (C.GlobalReference (ptr (FunctionType i32 [i32, i8] False)) (Name "foo"))),
+             arguments = [
+              (ConstantOperand (C.Int 32 1), [PA.InReg, PA.Alignment 16]),
+              (ConstantOperand (C.Int 8 4), [PA.SignExt])
+             ],
+             functionAttributes = [Left (FA.GroupID 0)],
+             metadata = []
+           }
+         ] (
+           Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+         )
+        ]
+      },
+      GlobalDefinition $ functionDefaults {
+        G.returnType = i32,
+        G.name = Name "baz",
+        G.prefix = Just (C.Int 32 1),
+        G.basicBlocks = [
+          BasicBlock (UnName 0) [
+           UnName 1 := Call {
+             tailCallKind = Just NoTail,
+             callingConvention = CC.C,
+             returnAttributes = [PA.ZeroExt],
+             function = Right (ConstantOperand (C.GlobalReference (ptr (FunctionType i32 [i32, i8] False)) (Name "foo"))),
+             arguments = [
+              (ConstantOperand (C.Int 32 1), [PA.InReg, PA.Alignment 16]),
+              (ConstantOperand (C.Int 8 4), [PA.SignExt])
+             ],
+             functionAttributes = [Left (FA.GroupID 0)],
+             metadata = []
+           }
+         ] (
+           Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+         )
+        ]
+      },
+      GlobalDefinition $ functionDefaults {
+        G.returnAttributes = [PA.ZeroExt],
+        G.returnType = i32,
+        G.name = Name "foo",
+        G.parameters = ([
+          Parameter i32 (Name "x") [PA.InReg, PA.Alignment 16],
+          Parameter i8 (Name "y") [PA.SignExt]
+         ], False),
+        G.functionAttributes = [Left (FA.GroupID 0)],
+        G.basicBlocks = [
+          BasicBlock (UnName 0) [
+           UnName 1 := Mul {
+             nsw = True,
+             nuw = False,
+             operand0 = LocalReference i32 (Name "x"),
+             operand1 = LocalReference i32 (Name "x"),
+             metadata = []
+           }
+           ] (
+             Do $ Br (Name "here") []
+           ),
+          BasicBlock (Name "here") [
+           Name "go" := ICmp {
+             iPredicate = IPred.EQ,
+             operand0 = LocalReference i32 (UnName 1),
+             operand1 = LocalReference i32 (Name "x"),
+             metadata = []
+           }
+           ] (
+              Do $ CondBr {
+                condition = LocalReference i1 (Name "go"),
+                trueDest = Name "there",
+                falseDest = Name "elsewhere",
+                metadata' = []
+              }
+           ),
+          BasicBlock (Name "there") [
+           UnName 2 := Add {
+             nsw = True,
+             nuw = False,
+             operand0 = LocalReference i32 (UnName 1),
+             operand1 = ConstantOperand (C.Int 32 3),
+             metadata = []
+           }
+           ] (
+             Do $ Br (Name "elsewhere") []
+           ),
+          BasicBlock (Name "elsewhere") [
+           Name "r" := Phi {
+             type' = i32,
+             incomingValues = [
+               (ConstantOperand (C.Int 32 2), Name "there"),
+               (ConstantOperand (C.Int 32 57), Name "here")
+             ],
+             metadata = []
+           }
+           ] (
+             Do $ Ret (Just (LocalReference i32 (Name "r"))) []
+           )
+         ]
+        },
+      FunctionAttributes (FA.GroupID 0) [FA.NoUnwind, FA.ReadNone, FA.UWTable, FA.StringAttribute "eep" ""],
+      COMDAT "bob" COMDAT.Largest
+     ]
+
+tests = testGroup "Module" [
+  testGroup "withModuleFromString" [
+    testCase "basic" $ withContext $ \context -> do
+      z <- withModuleFromLLVMAssembly' context handString (const $ return 0)
+      z @?= 0,
+    testCase "numbering" $ withContext $ \context -> do
+      let s = "@0 = global i32 3\
+              \define i32 @1(i32 %x) {\n\
+              \  %1 = mul i32 %x, %x\n\
+              \  %2 = add i32 %1, 3\n\
+              \  ret i32 %2\n\
+              \}\n"
+      z <- withModuleFromLLVMAssembly' context s (const $ return 0)
+      z @?= 0
+   ],
+
+  testGroup "emit" [
+    testCase "assemble" $ withContext $ \context -> do
+      let s = "define i32 @main(i32 %argc, i8** %argv) {\n\
+              \  ret i32 0\n\
+              \}\n"
+      a <- withModuleFromLLVMAssembly' context s $ \m -> do
+        (t, _) <- lookupTarget Nothing "x86_64-unknown-linux"
+        withTargetOptions $ \to -> do
+          withTargetMachine t "x86_64-unknown-linux" "" Map.empty to R.Default CM.Default CGO.Default $ \tm -> do
+            moduleTargetAssembly tm m
+      a @?= "\t.text\n\
+            \\t.file\t\"<string>\"\n\
+            \\t.globl\tmain\n\
+            \\t.p2align\t4, 0x90\n\
+            \\t.type\tmain,@function\n\
+            \main:\n\
+            \\t.cfi_startproc\n\
+            \\txorl\t%eax, %eax\n\
+            \\tretq\n\
+            \.Lfunc_end0:\n\
+            \\t.size\tmain, .Lfunc_end0-main\n\
+            \\t.cfi_endproc\n\
+            \\n\
+            \\t.section\t\".note.GNU-stack\",\"\",@progbits\n"
+   ],
+
+  testCase "handStringIsCanonical" $ withContext $ \context -> do
+    s <- withModuleFromLLVMAssembly' context handString moduleLLVMAssembly
+    s @?= handString,
+
+  testCase "moduleAST" $ withContext $ \context -> do
+    ast <- withModuleFromLLVMAssembly' context handString moduleAST
+    assertEqPretty ast handAST,
+    
+  testCase "withModuleFromAST" $ withContext $ \context -> do
+    s <- withModuleFromAST context handAST moduleLLVMAssembly
+    s @?= handString,
+
+  testCase "bitcode" $ withContext $ \context -> do
+    bs <- withModuleFromAST context handAST moduleBitcode
+    s <- withModuleFromBitcode' context bs moduleLLVMAssembly
+    s @?= handString,
+
+  testCase "triple" $ withContext $ \context -> do
+   let hAST = "; ModuleID = '<string>'\n\
+              \target triple = \"x86_64-unknown-linux\"\n"
+   ast <- withModuleFromLLVMAssembly' context hAST moduleAST
+   ast @?= defaultModule { moduleTargetTriple = Just "x86_64-unknown-linux" },
+
+  testGroup "regression" [
+    testCase "minimal type info" $ withContext $ \context -> do
+      let s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \define void @trouble() {\n\
+              \entry:\n\
+              \  ret void\n\
+              \\n\
+              \dead0:                                            ; preds = %dead1\n\
+              \  %x0 = add i32 %x1, %x1\n\
+              \  br label %dead1\n\
+              \\n\
+              \dead1:                                            ; preds = %dead0\n\
+              \  %x1 = add i32 %x0, %x0\n\
+              \  br label %dead0\n\
+              \}\n"
+          ast = Module "<string>" "<string>" Nothing Nothing [
+             GlobalDefinition $ functionDefaults {
+                G.returnType = T.void,
+                G.name = Name "trouble",
+                G.basicBlocks = [
+                 BasicBlock (Name "entry") [
+                  ] (
+                   Do $ Ret Nothing []
+                  ),
+                 BasicBlock (Name "dead0") [
+                   Name "x0" := Add {
+                     nsw = False,
+                     nuw = False,
+                     operand0 = LocalReference i32 (Name "x1"),
+                     operand1 = LocalReference i32 (Name "x1"),
+                     metadata = []
+                   }
+                  ] (
+                   Do $ Br (Name "dead1") []
+                  ),
+                 BasicBlock (Name "dead1") [
+                   Name "x1" := Add {
+                     nsw = False,
+                     nuw = False,
+                     operand0 = LocalReference i32 (Name "x0"),
+                     operand1 = LocalReference i32 (Name "x0"),
+                     metadata = []
+                   }
+                  ] (
+                   Do $ Br (Name "dead0") []
+                  )
+                 ]
+              }
+            ]
+      strCheck ast s
+      withContext $ \context -> withModuleFromAST context ast verify,
+
+    testCase "metadata type" $ withContext $ \context -> do
+      let s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \define void @bar(metadata %0) {\n\
+              \  ret void\n\
+              \}\n"
+          ast = Module "<string>" "<string>" Nothing Nothing [
+             GlobalDefinition $ functionDefaults {
+               G.returnType = void,
+               G.name = Name "bar",
+               G.parameters = ([Parameter MetadataType (UnName 0) []], False),
+               G.basicBlocks = [
+                 BasicBlock (UnName 1) [] (Do $ Ret Nothing [])
+                ]
+             }
+           ]
+      strCheck ast s,
+
+    testCase "set flag on constant expr" $ withContext $ \context -> do
+      let ast = Module "<string>" "<string>" Nothing Nothing [
+             GlobalDefinition $ functionDefaults {
+               G.returnType = i32,
+               G.name = Name "foo",
+               G.parameters = ([Parameter i32 (Name "x") []], False),
+               G.basicBlocks = [
+                 BasicBlock (UnName 0) [
+                  UnName 1 := Mul {
+                    nsw = True,
+                    nuw = False,
+                    operand0 = ConstantOperand (C.Int 32 1),
+                    operand1 = ConstantOperand (C.Int 32 1),
+                    metadata = []
+                  }
+                  ] (
+                    Do $ Br (Name "here") []
+                  ),
+                 BasicBlock (Name "here") [
+                  ] (
+                    Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+                  )
+                ]
+             }
+           ]
+      t <- withModuleFromAST context ast $ \_ -> return True
+      t @?= True,
+
+    testCase "Phi node finishes" $ withContext $ \context -> do
+      let ast = Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+              G.returnType = i32,
+              G.name = Name "foo",
+              G.parameters = ([Parameter i32 (Name "x") []], False),
+              G.basicBlocks = [
+                BasicBlock (UnName 0) [
+                 UnName 1 := Mul {
+                   nsw = True,
+                   nuw = False,
+                   operand0 = LocalReference i32 (Name "x"),
+                   operand1 = LocalReference i32 (Name "x"),
+                   metadata = []
+                 }
+                 ] (
+                   Do $ Br (Name "here") []
+                 ),
+                BasicBlock (Name "here") [
+                 UnName 2 := Phi i32 [ (ConstantOperand (C.Int 32 42), UnName 0) ] []
+                 ] (
+                   Do $ Br (Name "elsewhere") []
+                 ),
+                BasicBlock (Name "elsewhere") [             
+                 ] (
+                   Do $ Br (Name "there") []
+                 ),
+                BasicBlock (Name "there") [
+                 ] (
+                   Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+                 )
+               ]
+             }
+           ]
+          s = "; ModuleID = '<string>'\n\
+              \source_filename = \"<string>\"\n\
+              \\n\
+              \define i32 @foo(i32 %x) {\n\
+              \  %1 = mul nsw i32 %x, %x\n\
+              \  br label %here\n\
+              \\n\
+              \here:                                             ; preds = %0\n\
+              \  %2 = phi i32 [ 42, %0 ]\n\
+              \  br label %elsewhere\n\
+              \\n\
+              \elsewhere:                                        ; preds = %here\n\
+              \  br label %there\n\
+              \\n\
+              \there:                                            ; preds = %elsewhere\n\
+              \  ret i32 %1\n\
+              \}\n"
+      strCheck ast s,
+
+      testCase "switchblock" $ do
+        let count = 450
+            start = 2 -- won't come back the same w/o start = 2
+            ns = [start..count + start - 1]
+            vbps = zip [ ConstantOperand (C.Int 32 i) | i <- [0..] ] [ UnName n | n <- (1:ns) ]
+            cbps = zip [ C.Int 32 i | i <- [0..] ] [ UnName n | n <- ns ]
+
+        withContext $ \context -> do
+          let ast = Module "<string>" "<string>" Nothing Nothing [
+                GlobalDefinition $ functionDefaults {
+                  G.name = Name "foo",
+                  G.returnType = i32,
+                  G.parameters = ([Parameter i32 (UnName 0) []], False),
+                  G.basicBlocks = [
+                   BasicBlock (UnName 1) [] (Do $ Switch (LocalReference i32 (UnName 0)) (Name "end") cbps [])
+                  ] ++ [
+                   BasicBlock (UnName n) [] (Do $ Br (Name "end") []) | n <- ns
+                  ] ++ [
+                   BasicBlock (Name "end") [
+                     Name "val" := Phi i32 vbps []
+                   ] (
+                     Do $ Ret (Just (LocalReference i32 (Name "val"))) []
+                   )
+                  ]
+                }
+               ]
+          s <- withModuleFromAST context ast moduleLLVMAssembly
+          m <- withModuleFromLLVMAssembly' context s moduleAST
+          m @?= ast,
+
+      testCase "struct constant" $ do
+        let s = "; ModuleID = '<string>'\n\
+                \source_filename = \"<string>\"\n\
+                \\n\
+                \%0 = type { i32 }\n\
+                \\n\
+                \@0 = constant %0 { i32 1 }, align 4\n"
+            ast = Module "<string>" "<string>" Nothing Nothing [
+              TypeDefinition (UnName 0) (Just $ StructureType False [i32]),
+              GlobalDefinition $ globalVariableDefaults {
+                G.name = UnName 0,
+                G.isConstant = True,
+                G.type' = NamedTypeReference (UnName 0),
+                G.initializer = Just $ C.Struct (Just $ UnName 0) False [ C.Int 32 1 ],
+                G.alignment = 4
+              }
+             ]
+        strCheck ast s
+   ],
+        
+  testGroup "failures" [
+    testCase "bad block reference" $ withContext $ \context -> do
+      let badAST = Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+              G.returnType = i32,
+              G.name = Name "foo",
+              G.parameters = ([Parameter i32 (Name "x") []], False),
+              G.basicBlocks = [
+                BasicBlock (UnName 0) [
+                 UnName 1 := Mul {
+                   nsw = True,
+                   nuw = False,
+                   operand0 = ConstantOperand (C.Int 32 1),
+                   operand1 = ConstantOperand (C.Int 32 1),
+                   metadata = []
+                 }
+                 ] (
+                   Do $ Br (Name "not here") []
+                 ),
+                BasicBlock (Name "here") [
+                 ] (
+                   Do $ Ret (Just (LocalReference i32 (UnName 1))) []
+                 )
+               ]
+             }
+           ]
+      t <- try $ withModuleFromAST context badAST $ \_ -> return True
+      t @?= Left (EncodeException "reference to undefined block: Name \"not here\""),
+
+    testCase "multiple" $ withContext $ \context -> do
+      let badAST = Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+              G.returnType = i32,
+              G.name = Name "foo",
+              G.basicBlocks = [
+                BasicBlock (UnName 0) [
+                 UnName 1 := Mul {
+                   nsw = False,
+                   nuw = False,
+                   operand0 = LocalReference i32 (Name "unknown"),
+                   operand1 = ConstantOperand (C.Int 32 1),
+                   metadata = []
+                 },
+                 UnName 2 := Mul {
+                   nsw = False,
+                   nuw = False,
+                   operand0 = LocalReference i32 (Name "unknown2"),
+                   operand1 = LocalReference i32 (UnName 1),
+                   metadata = []
+                 }
+                 ] (
+                   Do $ Ret (Just (LocalReference i32 (UnName 2))) []
+                 )
+               ]
+             }
+           ]
+      t <- try $ withModuleFromAST context badAST $ \_ -> return True
+      t @?= Left (EncodeException "reference to undefined local: Name \"unknown\""),
+
+    testCase "sourceFileName" $ withContext $ \context -> do
+      let s = "; ModuleID = '<string>'\n\
+              \source_filename = \"filename\"\n"
+          ast = Module "<string>" "filename" Nothing Nothing []
+      strCheck ast s,
+
+    testCase "badTypeDef" $ withContext $ \context -> do
+      let badAST =
+            Module "<string>" "<string>" Nothing Nothing
+              [TypeDefinition (UnName 0) (Just VoidType)]
+      t <- try $ withModuleFromAST context badAST $ \_ -> return ()
+      t @?= Left (EncodeException "A type definition requires a structure type but got: VoidType"),
+    testCase "renamed type definitions" $ do
+      let modStr1 = unlines
+            [ "%struct = type { %struct* }"
+            , "define void @f(%struct*) {"
+            , "  ret void"
+            , "}"
+            ]
+          modAST1 = Module "<string>" "<string>" Nothing Nothing
+            [
+            ]
+          modStr2 = unlines
+            [ "%struct = type { %struct* }"
+            , "declare void @f(%struct*)"
+            , "define void @main() {"
+            , "  call void @f(%struct* zeroinitializer)"
+            , "  ret void"
+            , "}"
+            ]
+      ast1 <- withContext $ \ctx -> withModuleFromLLVMAssembly ctx modStr1 moduleAST
+      ast2 <- withContext $ \ctx -> withModuleFromLLVMAssembly ctx modStr2 moduleAST
+      (ast1', ast2') <- withContext $ \ctx ->
+        withModuleFromAST ctx ast1 $ \mod1 ->
+        withModuleFromAST ctx ast2 $ \mod2 ->
+          (,) <$> moduleAST mod1 <*> moduleAST mod2
+      withContext $ \ctx -> do
+        ast1'' <- withModuleFromLLVMAssembly ctx modStr1 moduleAST
+        ast2'' <- withModuleFromLLVMAssembly ctx modStr2 moduleAST
+        -- Verify that LLVM’s automatic renaming does not produce an error
+        -- and that the ASTs produced by llvm-hs and LLVM itself are the same.
+        ast1' @?= ast1''
+        ast2' @?= ast2''
+   ]
+ ]
diff --git a/test/LLVM/Test/ObjectCode.hs b/test/LLVM/Test/ObjectCode.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/ObjectCode.hs
@@ -0,0 +1,33 @@
+module LLVM.Test.ObjectCode where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import qualified Data.ByteString as ByteString
+import System.IO
+import System.IO.Temp
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.Target
+
+ll :: String
+ll = unlines ["define i32 @main(i32 %argc, i8** %argv) {", "  ret i32 0", "}"]
+
+tests =
+  testGroup
+    "Object code serialization"
+    [ testCase
+        "serialization to ByteString and to file" $ do
+        withContext $ \ctx ->
+          withSystemTempFile "foo" $ \objFile handle -> do
+            hClose handle
+            withHostTargetMachineDefault $ \machine ->
+              withModuleFromLLVMAssembly ctx ll $ \mdl -> do
+                obj <- moduleObject machine mdl
+                _ <- writeObjectToFile machine (File objFile) mdl
+                obj' <- ByteString.readFile objFile
+                obj @=? obj'
+    ]
diff --git a/test/LLVM/Test/Optimization.hs b/test/LLVM/Test/Optimization.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Optimization.hs
@@ -0,0 +1,344 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE PatternSynonyms #-}
+module LLVM.Test.Optimization where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import Data.Functor
+import Data.Monoid
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import LLVM.Module
+import LLVM.Context
+import LLVM.PassManager
+import qualified LLVM.Transforms as T
+import LLVM.Target
+
+import LLVM.AST as A
+import LLVM.AST.Type as A.T
+import LLVM.AST.Name
+import LLVM.AST.AddrSpace
+import LLVM.AST.DataLayout
+import qualified LLVM.AST.IntegerPredicate as IPred
+import qualified LLVM.AST.Linkage as L
+import qualified LLVM.AST.Visibility as V
+import qualified LLVM.AST.CallingConvention as CC
+import qualified LLVM.AST.Attribute as A
+import qualified LLVM.AST.Global as G
+import qualified LLVM.AST.Constant as C
+
+import qualified LLVM.Relocation as R
+import qualified LLVM.CodeModel as CM
+import qualified LLVM.CodeGenOpt as CGO
+
+import Debug.Trace
+
+handAST =
+  Module "<string>" "<string>" Nothing Nothing [
+      GlobalDefinition $ functionDefaults {
+        G.returnType = i32,
+        G.name = Name "foo",
+        G.parameters = ([Parameter i32 (Name "x") []], False),
+        G.functionAttributes = [Left (A.GroupID 0)],
+        G.basicBlocks = [
+          BasicBlock (UnName 0) [
+           UnName 1 := Mul {
+             nsw = False,
+             nuw = False,
+             operand0 = ConstantOperand (C.Int 32 6),
+             operand1 = ConstantOperand (C.Int 32 7),
+             metadata = []
+           }
+           ] (
+             Do $ Br (Name "here") []
+           ),
+          BasicBlock (Name "here") [
+           Name "go" := ICmp {
+             iPredicate = IPred.EQ,
+             operand0 = LocalReference i32 (UnName 1),
+             operand1 = ConstantOperand (C.Int 32 42),
+             metadata = []
+           }
+           ] (
+              Do $ CondBr {
+                condition = LocalReference i1 (Name "go"),
+                trueDest = Name "take",
+                falseDest = Name "done",
+                metadata' = []
+              }
+           ),
+          BasicBlock (Name "take") [
+           UnName 2 := Sub {
+             nsw = False,
+             nuw = False,
+             operand0 = LocalReference i32 (Name "x"),
+             operand1 = LocalReference i32 (Name "x"),
+             metadata = []
+           }
+           ] (
+             Do $ Br (Name "done") []
+           ),
+          BasicBlock (Name "done") [
+           Name "r" := Phi {
+             type' = i32,
+             incomingValues = [
+               (LocalReference i32 (UnName 2), Name "take"),
+               (ConstantOperand (C.Int 32 57), Name "here")
+             ],
+             metadata = []
+           }
+           ] (
+             Do $ Ret (Just (LocalReference i32 (Name "r"))) []
+           )
+         ]
+       },
+      FunctionAttributes (A.GroupID 0) [A.NoUnwind, A.ReadNone, A.UWTable]
+     ]
+
+pattern LLVMLoopIsVectorizedMetadata :: Integer -> Definition
+pattern LLVMLoopIsVectorizedMetadata i <- MetadataNodeDefinition _ (MDTuple [
+    Just (MDString "llvm.loop.isvectorized"),
+    Just (MDValue (ConstantOperand C.Int {C.integerBits = 32, C.integerValue = i}))
+  ])
+
+isVectorized :: A.Module -> Assertion
+isVectorized mod@Module { moduleDefinitions = defs } = do
+  let assertHasVectorTypedValues =
+        (@? "Module contains no vector-typed phi instructions") $
+          not $ null [ i
+              | GlobalDefinition Function { G.basicBlocks = b } <- defs,
+                BasicBlock _ is _ <- b,
+                _ := i@Phi { type' = VectorType _ _ } <- is
+            ]
+  let assertHasVectorizedMetadata =
+        (@? "Module is missing 'llvm.loop.isvectorized' metadata") $
+          not $ null [ 1
+              | LLVMLoopIsVectorizedMetadata 1 <- defs
+            ]
+  assertHasVectorTypedValues <> assertHasVectorizedMetadata
+
+optimize :: PassSetSpec -> A.Module -> IO A.Module
+optimize pss m = withContext $ \context -> withModuleFromAST context m $ \mIn' -> do
+  withPassManager pss $ \pm -> runPassManager pm mIn'
+  moduleAST mIn'
+
+tests = testGroup "Optimization" [
+  testCase "curated" $ do
+    mOut <- optimize defaultCuratedPassSetSpec handAST
+
+    mOut @?= Module "<string>" "<string>" Nothing Nothing [
+      GlobalDefinition $ functionDefaults {
+        G.returnType = i32,
+         G.name = Name "foo",
+         G.parameters = ([Parameter i32 (Name "x") []], False),
+         G.functionAttributes = [Left (A.GroupID 0)],
+         G.basicBlocks = [
+           BasicBlock (Name "here") [
+              ] (
+              Do $ Ret (Just (ConstantOperand (C.Int 32 0))) []
+            )
+          ]
+        },
+      FunctionAttributes (A.GroupID 0) [A.NoRecurse, A.NoUnwind, A.ReadNone, A.UWTable, A.WillReturn]
+      ],
+
+  testGroup "individual" [
+    testCase "InstSimplify" $ do
+      let
+        mIn = Module "<string>" "<string>" Nothing Nothing [
+           GlobalDefinition $ functionDefaults {
+            G.returnType = i32,
+             G.name = Name "foo",
+             G.parameters = ([Parameter i32 (Name "x") []], False),
+             G.functionAttributes = [Left (A.GroupID 0)],
+             G.basicBlocks = [
+               BasicBlock (UnName 0) [] (Do $ Br (Name "here") []),
+               BasicBlock (Name "here") [] (
+                  Do $ CondBr {
+                    condition = ConstantOperand (C.Int 1 1),
+                    trueDest = Name "take",
+                    falseDest = Name "done",
+                    metadata' = []
+                  }
+               ),
+               BasicBlock (Name "take") [] (
+                Do $ Br (Name "done") []
+               ),
+               BasicBlock (Name "done") [
+                Name "r" := Phi {
+                  type' = i32,
+                  incomingValues = [(ConstantOperand (C.Int 32 0), Name "take"), (ConstantOperand (C.Int 32 57), Name "here")],
+                  metadata = []
+                 }
+               ] (
+                 Do $ Ret (Just (LocalReference i32 (Name "r"))) []
+               )
+              ]
+            },
+           FunctionAttributes (A.GroupID 0) [A.NoUnwind, A.ReadNone, A.UWTable]
+          ]
+      mOut <- optimize defaultPassSetSpec { transforms = [T.InstructionSimplify] } handAST
+      mOut @?= mIn,
+
+    testCase "SLPVectorization" $ do
+      let
+        fadd op0 op1 =
+          FAdd { fastMathFlags = noFastMathFlags, operand0 = op0, operand1 = op1, metadata = [] }
+        doubleVec = VectorType 2 double
+        constInt i = ConstantOperand (C.Int {C.integerBits = 32, C.integerValue = i})
+        undef = ConstantOperand (C.Undef doubleVec)
+        extractElement vec index' =
+          ExtractElement { vector = vec, index = index', metadata = [] }
+        insertElement vec el i =
+          InsertElement { vector = vec, element = el, index = i, metadata = [] }
+        mIn = Module "<string>" "<string>" Nothing Nothing [
+          GlobalDefinition $ functionDefaults {
+           G.returnType = doubleVec,
+            G.name = Name "buildVector_add_2f64",
+            G.parameters = ([
+              Parameter doubleVec n []
+                | n <- [ "a", "b" ]
+             ], False),
+            G.basicBlocks = [
+              BasicBlock (UnName 0)
+                ["a0" := extractElement (LocalReference doubleVec "a") (constInt 0),
+                 "a1" := extractElement (LocalReference doubleVec "a") (constInt 1),
+                 "b0" := extractElement (LocalReference doubleVec "b") (constInt 0),
+                 "b1" := extractElement (LocalReference doubleVec "b") (constInt 1),
+                 "c0" := fadd (LocalReference double "a0") (LocalReference double "b0"),
+                 "c1" := fadd (LocalReference double "a1") (LocalReference double "b1"),
+                 "r0" := insertElement undef (LocalReference double "c0") (constInt 0),
+                 "r1" := insertElement (LocalReference doubleVec "r0") (LocalReference double "c1") (constInt 1)
+                ]
+                (Do (Ret (Just (LocalReference doubleVec "r1")) []))
+             ]
+          }
+         ]
+      mOut <- optimize (defaultPassSetSpec {
+                    transforms = [
+                     T.SuperwordLevelParallelismVectorize,
+                     T.InstructionCombining,
+                     T.GlobalValueNumbering False
+                    ] }) mIn
+      mOut @?=
+        Module "<string>" "<string>" Nothing Nothing [
+            GlobalDefinition $ functionDefaults {
+             G.returnType = doubleVec,
+              G.name = Name "buildVector_add_2f64",
+              G.parameters = ([
+                Parameter doubleVec n []
+                  | n <- [ "a", "b" ]
+               ], False),
+              G.basicBlocks = [
+                BasicBlock (UnName 0)
+                  [UnName 1 := fadd (LocalReference doubleVec "a") (LocalReference doubleVec "b")]
+                  (Do (Ret (Just (LocalReference doubleVec (UnName 1))) []))
+               ]
+            }
+           ],
+
+    testCase "LoopVectorize" $ do
+      let
+        mIn =
+          Module {
+            moduleName = "<string>",
+            moduleSourceFileName = "<string>",
+            moduleDataLayout = Just $ (defaultDataLayout BigEndian) {
+              typeLayouts = Map.singleton (VectorAlign, 128) (AlignmentInfo 128 128)
+             },
+            moduleTargetTriple = Just "x86_64",
+            moduleDefinitions = [
+              GlobalDefinition $ globalVariableDefaults {
+                G.name = Name "a",
+                G.linkage = L.Common,
+                G.type' = A.T.ArrayType 2048 i32,
+                G.initializer = Just (C.AggregateZero (A.T.ArrayType 2048 i32))
+               },
+              GlobalDefinition $ functionDefaults {
+                G.returnType = A.T.void,
+                G.name = Name "inc",
+                G.functionAttributes = [Left (A.GroupID 0)],
+                G.parameters = ([Parameter i32 (Name "n") []], False),
+                G.basicBlocks = [
+                  BasicBlock (UnName 0) [
+                    UnName 1 := ICmp IPred.SGT (LocalReference i32 (Name "n")) (ConstantOperand (C.Int 32 0)) []
+                   ] (Do $ CondBr (LocalReference i1 (UnName 1)) (Name ".lr.ph") (Name "._crit_edge") []),
+                  BasicBlock (Name ".lr.ph") [
+                    Name "indvars.iv" := Phi i64 [
+                      (ConstantOperand (C.Int 64 0), UnName 0),
+                      (LocalReference i64 (Name "indvars.iv.next"), Name ".lr.ph")
+                     ] [],
+                    UnName 2 := GetElementPtr True (ConstantOperand (C.GlobalReference (PointerType (A.T.ArrayType 2048 i32) (AddrSpace 0)) (Name "a"))) [
+                      ConstantOperand (C.Int 64 0),
+                      LocalReference i64 (Name "indvars.iv")
+                     ] [],
+                    UnName 3 := Load False (LocalReference (ptr i32) (UnName 2)) Nothing 4 [],
+                    UnName 4 := Trunc (LocalReference i64 (Name "indvars.iv")) i32 [],
+                    UnName 5 := Add True False (LocalReference i32 (UnName 3)) (LocalReference i32 (UnName 4)) [],
+                    Do $ Store False (LocalReference (ptr i32) (UnName 2)) (LocalReference i32 (UnName 5)) Nothing 4 [],
+                    Name "indvars.iv.next" := Add False False (LocalReference i64 (Name "indvars.iv")) (ConstantOperand (C.Int 64 1)) [],
+                    Name "lftr.wideiv" := Trunc (LocalReference i64 (Name "indvars.iv.next")) i32 [],
+                    Name "exitcond" := ICmp IPred.EQ (LocalReference i32 (Name "lftr.wideiv")) (LocalReference i32 (Name "n")) []
+                   ] (Do $ CondBr (LocalReference i1 (Name "exitcond")) (Name "._crit_edge") (Name ".lr.ph") []),
+                  BasicBlock (Name "._crit_edge") [
+                   ] (Do $ Ret Nothing [])
+                 ]
+               },
+              FunctionAttributes (A.GroupID 0) [A.NoUnwind, A.ReadNone, A.UWTable, A.StackProtect]
+             ]
+           }
+      mOut <- do
+        initializeAllTargets
+        let triple = "x86_64"
+        (target, _) <- lookupTarget Nothing triple
+        withTargetOptions $ \targetOptions -> do
+          withTargetMachine target triple "" Map.empty targetOptions R.Default CM.Default CGO.Default $ \tm -> do
+            optimize (defaultPassSetSpec {
+                        transforms = [ T.defaultLoopVectorize ],
+                        dataLayout = moduleDataLayout mIn,
+                        targetMachine = Just tm
+                      }) mIn
+      isVectorized mOut,
+
+    testCase "LowerInvoke" $ do
+      -- This test doesn't test much about what LowerInvoke does, just that it seems to work.
+      -- The pass seems to be quite deeply dependent on weakly documented presumptions about
+      -- how unwinding works (as is the invoke instruction)
+      withContext $ \context -> do
+        withPassManager (defaultPassSetSpec { transforms = [T.LowerInvoke] }) $ \passManager -> do
+          let astIn =
+                Module "<string>" "<string>" Nothing Nothing [
+                  GlobalDefinition $ functionDefaults {
+                    G.returnType = i32,
+                    G.name = Name "foo",
+                    G.parameters = ([Parameter i32 (Name "x") []], False),
+                    G.basicBlocks = [
+                      BasicBlock (Name "here") [
+                      ] (
+                        Do $ Ret (Just (ConstantOperand (C.Int 32 0))) []
+                      )
+                     ]
+                   }
+                 ]
+          astOut <- withModuleFromAST context astIn $ \mIn -> do
+            runPassManager passManager mIn
+            moduleAST mIn
+          astOut @?= Module "<string>" "<string>" Nothing Nothing [
+                  GlobalDefinition $ functionDefaults {
+                    G.returnType = i32,
+                    G.name = Name "foo",
+                    G.parameters = ([Parameter i32 (Name "x") []], False),
+                    G.basicBlocks = [
+                      BasicBlock (Name "here") [
+                      ] (
+                        Do $ Ret (Just (ConstantOperand (C.Int 32 0))) []
+                      )
+                    ]
+                  }
+                 ]
+   ]
+ ]
diff --git a/test/LLVM/Test/OrcJIT.hs b/test/LLVM/Test/OrcJIT.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/OrcJIT.hs
@@ -0,0 +1,211 @@
+{-# LANGUAGE ForeignFunctionInterface, OverloadedStrings #-}
+module LLVM.Test.OrcJIT where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import LLVM.Test.Support
+
+import qualified Data.Map.Strict as Map
+import Control.Applicative
+import Data.ByteString (ByteString)
+import Data.Foldable
+import Data.Int
+import Data.IORef
+import Data.Word
+import Foreign.Ptr
+import Foreign.Storable
+import Foreign.Marshal.Alloc
+import System.Process (callProcess)
+import System.IO.Temp (withSystemTempFile)
+import System.IO
+
+import LLVM.Internal.PassManager
+import LLVM.Internal.ObjectFile (withObjectFile)
+import LLVM.PassManager
+import LLVM.Context
+import LLVM.Module
+import LLVM.OrcJIT
+import LLVM.Target
+import qualified LLVM.Relocation as Reloc
+import qualified LLVM.CodeModel as CodeModel
+import qualified LLVM.CodeGenOpt as CodeGenOpt
+
+testModule :: ByteString
+testModule =
+  "; ModuleID = '<string>'\n\
+  \source_filename = \"<string>\"\n\
+  \\n\
+  \declare i32 @testFunc()\n\
+  \define i32 @main(i32, i8**) {\n\
+  \  %3 = call i32 @testFunc()\n\
+  \  ret i32 %3\n\
+  \}\n"
+
+test2Module :: ByteString
+test2Module =
+  "; ModuleID = '<string>'\n\
+  \source_filename = \"<string>\"\n\
+  \\n\
+  \define i32 @main() {\n\
+  \  ret i32 42\n\
+  \}\n"
+
+test3Module :: ByteString
+test3Module =
+  "; ModuleID = '<string>'\n\
+  \source_filename = \"<string>\"\n\
+  \@data = external global i32\n\
+  \\n\
+  \define i32 @main() {\n\
+  \  %1 = load i32, i32* @data\n\
+  \  ret i32 %1\n\
+  \}\n"
+
+withTestModule :: ByteString -> (Module -> IO a) -> IO a
+withTestModule txt f = withContext $ \context -> withModuleFromLLVMAssembly' context txt f
+
+myTestFuncImpl :: IO Word32
+myTestFuncImpl = return 42
+
+foreign import ccall "wrapper"
+  wrapTestFunc :: IO Word32 -> IO (FunPtr (IO Word32))
+
+foreign import ccall "dynamic"
+  mkMain :: FunPtr (IO Word32) -> IO Word32
+
+tests :: TestTree
+tests =
+  testGroup "OrcJIT" [
+    testCase "basic self-contained function" $ do
+      withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+        withExecutionSession $ \es -> do
+          ol <- createRTDyldObjectLinkingLayer es
+          il <- createIRCompileLayer es ol tm
+          dylib <- createJITDylib es "testDylib"
+          withTestModule test2Module $ \m ->
+            withClonedThreadSafeModule m $ \tsm -> do
+              addModule tsm dylib il
+              Right (JITSymbol addr _) <- lookupSymbol es il dylib "main"
+              let mainFn = mkMain (castPtrToFunPtr $ wordPtrToPtr $ fromIntegral addr)
+              result <- mainFn
+              result @?= 42,
+
+    testCase "basic self-contained function + ObjectLinkingLayer" $ do
+      withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+        withExecutionSession $ \es -> do
+          ol <- createObjectLinkingLayer es
+          il <- createIRCompileLayer es ol tm
+          dylib <- createJITDylib es "testDylib"
+          withTestModule test2Module $ \m ->
+            withClonedThreadSafeModule m $ \tsm -> do
+              addModule tsm dylib il
+              Right (JITSymbol addr _) <- lookupSymbol es il dylib "main"
+              let mainFn = mkMain (castPtrToFunPtr $ wordPtrToPtr $ fromIntegral addr)
+              result <- mainFn
+              result @?= 42,
+
+    testCase "using symbols in external shared libraries" $
+      withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+        withExecutionSession $ \es -> do
+          ol <- createRTDyldObjectLinkingLayer es
+          il <- createIRCompileLayer es ol tm
+          dylib <- createJITDylib es "testDylib"
+          let inputPath = "./test/main_return_38.c"
+          withSystemTempFile "main.o" $ \outputPath _ -> do
+            callProcess "gcc" ["-shared", "-fPIC", inputPath, "-o", outputPath]
+            addDynamicLibrarySearchGenerator il dylib outputPath
+            Right (JITSymbol mainFn _) <- lookupSymbol es il dylib "main"
+            result <- mkMain (castPtrToFunPtr (wordPtrToPtr mainFn))
+            result @?= 38,
+
+    testCase "run optimization passes on a JIT module" $ do
+      passmanagerSuccessful <- newIORef False
+      withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+        withExecutionSession $ \es -> do
+          ol <- createRTDyldObjectLinkingLayer es
+          il <- createIRCompileLayer es ol tm
+          dylib <- createJITDylib es "testDylib"
+          withTestModule test2Module $ \m -> do
+           withPassManager defaultCuratedPassSetSpec { optLevel = Just 2 } $ \pm -> do
+             success <- runPassManager pm m
+             writeIORef passmanagerSuccessful success
+             withClonedThreadSafeModule m $ \tsm -> do
+               addModule tsm dylib il
+               Right (JITSymbol mainFn _) <- lookupSymbol es il dylib "main"
+               result <- mkMain (castPtrToFunPtr (wordPtrToPtr mainFn))
+               result @?= 42
+               readIORef passmanagerSuccessful @? "passmanager failed",
+
+    testCase "defining absolute symbols" $ do
+      withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+        withExecutionSession $ \es -> do
+          ol <- createRTDyldObjectLinkingLayer es
+          il <- createIRCompileLayer es ol tm
+          alloca $ \ptr -> do
+            poke ptr (1234 :: Int32)
+            dylib <- createJITDylib es "testDylib"
+            withMangledSymbol il "data" $ \dataSym -> do
+              let flags = defaultJITSymbolFlags { jitSymbolAbsolute = True }
+              defineAbsoluteSymbols dylib [(dataSym, JITSymbol (ptrToWordPtr ptr) flags)]
+              withTestModule test3Module $ \m -> do
+                withClonedThreadSafeModule m $ \tsm -> do
+                  addModule tsm dylib il
+                  Right (JITSymbol addr _) <- lookupSymbol es il dylib "main"
+                  let mainFn = mkMain (castPtrToFunPtr $ wordPtrToPtr $ fromIntegral addr)
+                  result <- mainFn
+                  result @?= 1234
+
+    -- TODO: Make it possible to use Haskell functions as definition generators
+    --       and update to OrcJITv2
+    {-
+     testCase "eager compilation" $ do
+       withTestModule $ \mod ->
+         withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm ->
+         withExecutionSession $ \es ->
+         withObjectLinkingLayer es (\k -> fmap (\rs -> rs Map.! k) (readIORef resolvers)) $ \linkingLayer ->
+         withIRCompileLayer linkingLayer tm $ \compileLayer -> do
+           testFunc <- mangleSymbol compileLayer "testFunc"
+           withModuleKey es $ \k ->
+             withSymbolResolver es (SymbolResolver (resolver testFunc compileLayer)) $ \resolver -> do
+               modifyIORef' resolvers (Map.insert k resolver)
+               withModule compileLayer k mod $ do
+                 mainSymbol <- mangleSymbol compileLayer "main"
+                 Right (JITSymbol mainFn _) <- CL.findSymbol compileLayer mainSymbol True
+                 result <- mkMain (castPtrToFunPtr (wordPtrToPtr mainFn))
+                 result @?= 42
+                 Right (JITSymbol mainFn _) <- CL.findSymbolIn compileLayer k mainSymbol True
+                 result <- mkMain (castPtrToFunPtr (wordPtrToPtr mainFn))
+                 result @?= 42
+                 unknownSymbol <- mangleSymbol compileLayer "unknownSymbol"
+                 unknownSymbolRes <- CL.findSymbol compileLayer unknownSymbol True
+                 unknownSymbolRes @?= Left (JITSymbolError mempty),
+    -}
+
+    -- TODO: Add IRTransformLayer and translate to OrcJITv2
+    {-
+    testCase "lazy compilation" $ do
+      resolvers <- newIORef Map.empty
+      let getResolver k = fmap (Map.! k) (readIORef resolvers)
+          setResolver k r = modifyIORef' resolvers (Map.insert k r)
+      withTestModule $ \mod ->
+        withHostTargetMachine Reloc.PIC CodeModel.Default CodeGenOpt.Default $ \tm -> do
+          triple <- getTargetMachineTriple tm
+          withExecutionSession $ \es ->
+            withObjectLinkingLayer es getResolver $ \linkingLayer ->
+            withIRCompileLayer linkingLayer tm $ \baseLayer ->
+            withIndirectStubsManagerBuilder triple $ \stubsMgr ->
+            withJITCompileCallbackManager es triple Nothing $ \callbackMgr ->
+            withCompileOnDemandLayer es baseLayer tm getResolver setResolver (\x -> return [x]) callbackMgr stubsMgr False $ \compileLayer -> do
+              testFunc <- mangleSymbol compileLayer "testFunc"
+              withModuleKey es $ \k ->
+                withSymbolResolver es (SymbolResolver (resolver testFunc baseLayer)) $ \resolver -> do
+                  setResolver k resolver
+                  withModule compileLayer k mod $ do
+                    mainSymbol <- mangleSymbol compileLayer "main"
+                    Right (JITSymbol mainFn _) <- CL.findSymbol compileLayer mainSymbol True
+                    result <- mkMain (castPtrToFunPtr (wordPtrToPtr mainFn))
+                    result @?= 42,
+    -}
+
+    ]
diff --git a/test/LLVM/Test/ParameterAttribute.hs b/test/LLVM/Test/ParameterAttribute.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/ParameterAttribute.hs
@@ -0,0 +1,67 @@
+{-# LANGUAGE LambdaCase #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+module LLVM.Test.ParameterAttribute where
+
+import Test.Tasty
+import Test.Tasty.QuickCheck                              hiding ( (.&.) )
+
+import LLVM.Test.Support
+
+import LLVM.AST.ParameterAttribute
+import LLVM.Internal.Coding
+import LLVM.Internal.Context
+import LLVM.Internal.EncodeAST
+import LLVM.Internal.DecodeAST
+import qualified LLVM.Internal.FFI.Attribute              as FFI
+
+import Control.Applicative
+import Data.Bits
+import Data.List
+import Data.Word
+import Text.Show.Pretty
+import Control.Monad.IO.Class (liftIO)
+import Prelude
+import qualified Data.ByteString.Short                    as B
+
+
+instance Arbitrary ParameterAttribute where
+  arbitrary = oneof
+    [ return ZeroExt
+    , return SignExt
+    , return InReg
+    , return SRet
+    , Alignment <$> elements (map (2^) [0..30 :: Int])
+    , return NoAlias
+    , return ByVal
+    , return NoCapture
+    , return NoFree
+    , return Nest
+    , return ReadNone
+    , return ReadOnly
+    , return WriteOnly
+    , return ImmArg
+    , return InAlloca
+    , return NonNull
+    , Dereferenceable <$> suchThat arbitrary (/= 0)
+    , DereferenceableOrNull <$> suchThat arbitrary (/= 0)
+    , return Returned
+    , return SwiftSelf
+    , return SwiftError
+    , StringAttribute <$> arbitrarySbs <*> arbitrarySbs
+    ]
+
+
+tests :: TestTree
+tests =
+  testGroup "ParameterAttribute"
+    [ testProperty "round-trip"  $ \attr ->
+        ioProperty $ withContext $ \ctx  -> do
+          attr' <- runEncodeAST ctx $ do
+            attrSet <- encodeM [attr] :: EncodeAST FFI.ParameterAttributeSet
+            liftIO (runDecodeAST (decodeM attrSet :: DecodeAST [ParameterAttribute]))
+          return $ counterexample (unlines [ "expected: " ++ ppShow [attr]
+                                           , "but got:  " ++ ppShow attr'
+                                           ])
+                                  ([attr] == attr')
+    ]
diff --git a/test/LLVM/Test/Regression.hs b/test/LLVM/Test/Regression.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Regression.hs
@@ -0,0 +1,231 @@
+{-# LANGUAGE OverloadedStrings #-}
+module LLVM.Test.Regression
+  ( tests
+  ) where
+
+import           Test.Tasty
+import           Test.Tasty.HUnit
+
+import qualified LLVM.AST as AST
+import           LLVM.AST hiding (Module)
+import qualified LLVM.AST.Constant as C
+import           LLVM.AST.Global hiding (metadata)
+import           LLVM.AST.Type
+import           LLVM.IRBuilder
+
+import           LLVM.Context
+import           LLVM.Exception
+import           LLVM.Module
+
+import           Data.ByteString as B (readFile)
+import           Control.Exception
+
+example1 :: AST.Module
+example1 =
+  defaultModule
+  { moduleDefinitions =
+      [ GlobalDefinition
+          functionDefaults
+          { name = "test"
+          , returnType = void
+          , basicBlocks =
+              [ BasicBlock
+                  "entry"
+                  [ UnName 0 := Alloca i32 Nothing 0 []
+                  , UnName 1 :=
+                    Store
+                      False
+                      (LocalReference (ptr i32) (UnName 0))
+                      (ConstantOperand (C.Int 32 42))
+                      Nothing
+                      0
+                      []
+                  ]
+                  (Do $ Ret Nothing [])
+              ]
+          }
+      ]
+  }
+
+example2 :: AST.Module
+example2 =
+  defaultModule
+  { moduleDefinitions =
+      [ GlobalDefinition
+          functionDefaults
+          { name = "test"
+          , returnType = void
+          , basicBlocks =
+              [ BasicBlock
+                  "entry"
+                  [ UnName 0 :=
+                    Alloca (ptr $ FunctionType void [] False) Nothing 0 []
+                  , Do $
+                    Store
+                      False
+                      (LocalReference
+                         (ptr $ ptr $ FunctionType void [] False)
+                         (UnName 0))
+                      (ConstantOperand $
+                       C.GlobalReference (FunctionType void [] False) "test")
+                      Nothing
+                      0
+                      []
+                  ]
+                  (Do $ Ret Nothing [])
+              ]
+          }
+      ]
+  }
+
+example3 :: AST.Module
+example3 =
+  defaultModule
+  { moduleDefinitions =
+      [ GlobalDefinition
+          functionDefaults
+          { name = "test"
+          , returnType = void
+          , basicBlocks =
+              [ BasicBlock
+                  "entry"
+                  [ UnName 0 := GetElementPtr {
+                      inBounds = False,
+                      address = ConstantOperand (C.Null i32),
+                      indices = [ ConstantOperand (C.Int 32 0) ],
+                      metadata = []
+                    }
+                  ]
+                  (Do $ Ret Nothing [])
+              ]
+          }
+      ]
+  }
+
+duplicateDefinitions :: AST.Module
+duplicateDefinitions =
+  defaultModule
+    { moduleName = "clashingModule"
+    , moduleDefinitions =
+        [ GlobalDefinition
+            functionDefaults
+              { name = "clashy"
+              , returnType = i64
+              , basicBlocks =
+                  [ BasicBlock
+                      "entry"
+                      [ mkName "c" :=
+                        Add
+                          False
+                          False
+                          (ConstantOperand (C.Int 64 1))
+                          (ConstantOperand (C.Int 64 2))
+                          []
+                      ]
+                      (Do (Br "next" []))
+                  , BasicBlock
+                      "next"
+                      [ mkName "c" :=
+                        Phi i64 [(LocalReference i64 "c", "entry")] []
+                      ]
+                      (Do (Ret (Just (LocalReference i64 "c")) []))
+                  ]
+              }
+        ]
+    }
+
+reuseAcrossFunctions :: AST.Module
+reuseAcrossFunctions =
+  defaultModule
+    { moduleName = "<string>"
+    , moduleDefinitions =
+        [ GlobalDefinition
+            functionDefaults
+              { name = "f"
+              , returnType = i64
+              , basicBlocks =
+                  [ BasicBlock
+                      "entry"
+                      [ "c" :=
+                        Add
+                          False
+                          False
+                          (ConstantOperand (C.Int 64 1))
+                          (ConstantOperand (C.Int 64 2))
+                          []
+                      ]
+                      (Do (Ret (Just (LocalReference i64 "c")) []))
+                  ]
+              }
+        , GlobalDefinition
+            functionDefaults
+              { name = "g"
+              , returnType = i64
+              , basicBlocks =
+                  [ BasicBlock
+                      "entry"
+                      [ "c" :=
+                        Add
+                          False
+                          False
+                          (ConstantOperand (C.Int 64 1))
+                          (ConstantOperand (C.Int 64 2))
+                          []
+                      ]
+                      (Do (Ret (Just (LocalReference i64 "c")) []))
+                  ]
+              }
+        ]
+    }
+
+shouldThrowEncodeException :: AST.Module -> String -> IO ()
+shouldThrowEncodeException ast errMsg = do
+  result <- try $ withContext $ \context -> do
+    withModuleFromAST context ast (\_ -> return ())
+  case result of
+    Left (EncodeException actualErrMsg) -> actualErrMsg @?= errMsg
+    Right _ -> assertFailure ("Expected serialization to fail with: \"" ++ errMsg ++ "\"")
+
+shouldNotThrow :: AST.Module -> IO ()
+shouldNotThrow ast = do
+  withContext $ \context -> do
+    withModuleFromAST context ast (\_ -> return ())
+
+emptyName :: AST.Module
+emptyName = defaultModule { moduleDefinitions = defs }
+  where defs = execModuleBuilder emptyModuleBuilder (extern "f" [i32, i64] void)
+
+tests :: TestTree
+tests =
+  testGroup
+    "Regression"
+    [ testCase
+        "no named voids"
+        (example1 `shouldThrowEncodeException`
+         "Instruction of type void must not have a name: UnName 1 := Store {volatile = False, address = LocalReference (PointerType {pointerReferent = IntegerType {typeBits = 32}, pointerAddrSpace = AddrSpace 0}) (UnName 0), value = ConstantOperand (Int {integerBits = 32, integerValue = 42}), maybeAtomicity = Nothing, alignment = 0, metadata = []}")
+    , testCase
+        "no implicit casts"
+        (example2 `shouldThrowEncodeException`
+         "The serialized GlobalReference Name \"test\" has type FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False} but should have type PointerType {pointerReferent = FunctionType {resultType = VoidType, argumentTypes = [], isVarArg = False}, pointerAddrSpace = AddrSpace 0}")
+    , testCase
+        "null constants must have pointer type"
+        (example3 `shouldThrowEncodeException`
+          "Null pointer constant must have pointer type but has type IntegerType {typeBits = 32}.")
+    , testCase
+        "Duplicate definitions are not allowed"
+        (duplicateDefinitions `shouldThrowEncodeException`
+          "Duplicate definition of local variable: Name \"c\".")
+    , testCase
+        "Reusing variable names across functions is allowed"
+        (shouldNotThrow reuseAcrossFunctions)
+    , testCase
+        "Empty names do not collide" $ do
+           moduleStr <- withContext $ \cxt -> withModuleFromAST cxt emptyName moduleLLVMAssembly
+           moduleStr @?= "; ModuleID = '<string>'\nsource_filename = \"<string>\"\n\ndeclare void @f(i32, i64)\n"
+--    , testCase
+--        "FNeg is parsed correctly" $ do
+--           fStr <- B.readFile "test/fneg_test.ll"
+--           withContext $ \context -> do
+--             a <- withModuleFromLLVMAssembly context fStr moduleAST
+--             pure ()
+    ]
diff --git a/test/LLVM/Test/Support.hs b/test/LLVM/Test/Support.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Support.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE FlexibleContexts     #-}
+{-# LANGUAGE FlexibleInstances    #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+
+module LLVM.Test.Support where
+
+import LLVM.Prelude
+
+import Test.Tasty
+import Test.Tasty.HUnit
+import Test.QuickCheck
+
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Short as BSS
+import Data.Functor
+import Control.Monad
+import Control.Monad.Trans.Except
+import Text.Show.Pretty
+
+import LLVM.Context
+import LLVM.Module
+import LLVM.Diagnostic
+
+withModuleFromLLVMAssembly' :: Context -> ByteString -> (Module -> IO a) -> IO a
+withModuleFromLLVMAssembly' c s f  = withModuleFromLLVMAssembly c s f
+withModuleFromBitcode' c a f = withModuleFromBitcode c ("<string>", a) f
+
+assertEqPretty :: (Eq a, Show a) => a -> a -> Assertion
+assertEqPretty actual expected = do
+  assertBool
+   ("expected: " ++ ppShow expected ++ "\n" ++ "but got: " ++ ppShow actual ++ "\n")
+   (expected == actual)
+
+strCheckC mAST mStr mStrCanon = withContext $ \context -> do
+  a <- withModuleFromLLVMAssembly' context mStr moduleAST
+  s <- withModuleFromAST context mAST moduleLLVMAssembly
+  (a,s) `assertEqPretty` (mAST, mStrCanon)
+
+strCheck mAST mStr = strCheckC mAST mStr mStr
+
+arbitrarySbs :: Gen ShortByteString
+arbitrarySbs = BSS.pack <$> listOf arbitrary
diff --git a/test/LLVM/Test/Target.hs b/test/LLVM/Test/Target.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Target.hs
@@ -0,0 +1,166 @@
+{-# LANGUAGE
+  CPP,
+  OverloadedStrings,
+  RecordWildCards,
+  ScopedTypeVariables
+  #-}
+module LLVM.Test.Target where
+
+import           Test.Tasty
+import           Test.Tasty.HUnit
+import           Test.Tasty.QuickCheck
+import           Test.QuickCheck
+
+import           Control.Applicative
+import           Control.Monad
+import           Control.Monad.IO.Class
+import qualified Data.ByteString.Char8 as ByteString
+import           Data.Char
+import           Data.Map (Map)
+import           Data.Monoid (mempty)
+import           Foreign.C.String
+
+import qualified LLVM.CodeGenOpt as CodeGenOpt
+import qualified LLVM.CodeModel as CodeModel
+import           LLVM.Context
+import           LLVM.Internal.Coding
+import           LLVM.Internal.DecodeAST
+import           LLVM.Internal.EncodeAST
+import qualified LLVM.Relocation as Reloc
+import           LLVM.Target
+import           LLVM.Target.LibraryFunction
+import           LLVM.Target.Options
+
+instance Arbitrary FloatABI where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary FloatingPointOperationFusionMode where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary ThreadModel where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary EABIVersion where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary DebuggerKind where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary FloatingPointDenormalMode where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary ExceptionHandling where
+  arbitrary = elements [minBound .. maxBound]
+
+instance Arbitrary Options where
+  arbitrary = do
+    unsafeFloatingPointMath <- arbitrary
+    noInfinitiesFloatingPointMath <- arbitrary
+    noNaNsFloatingPointMath <- arbitrary
+    noTrappingFloatingPointMath <- arbitrary
+    noSignedZeroesFloatingPointMath <- arbitrary
+    honorSignDependentRoundingFloatingPointMathOption <- arbitrary
+    noZerosInBSS <- arbitrary
+    guaranteedTailCallOptimization <- arbitrary
+    stackSymbolOrdering <- arbitrary
+    enableFastInstructionSelection <- arbitrary
+    useInitArray <- arbitrary
+    disableIntegratedAssembler <- arbitrary
+    compressDebugSections <- arbitrary
+    relaxELFRelocations <- arbitrary
+    functionSections <- arbitrary
+    dataSections <- arbitrary
+    uniqueSectionNames <- arbitrary
+    trapUnreachable <- arbitrary
+    emulatedThreadLocalStorage <- arbitrary
+    enableInterProceduralRegisterAllocation <- arbitrary
+    stackAlignmentOverride <- arbitrary
+    floatABIType <- arbitrary
+    allowFloatingPointOperationFusion <- arbitrary
+    threadModel <- arbitrary
+    eabiVersion <- arbitrary
+    debuggerTuning <- arbitrary
+    floatingPointDenormalMode <- arbitrary
+    exceptionModel <- arbitrary
+    machineCodeOptions <- arbitrary
+    return Options { .. }
+
+instance Arbitrary MachineCodeOptions where
+  arbitrary = do
+    relaxAll <- arbitrary
+    noExecutableStack <- arbitrary
+    fatalWarnings <- arbitrary
+    noWarnings <- arbitrary
+    noDeprecatedWarning <- arbitrary
+    saveTemporaryLabels <- arbitrary
+    useDwarfDirectory <- arbitrary
+    incrementalLinkerCompatible <- arbitrary
+    showMachineCodeEncoding <- arbitrary
+    showMachineCodeInstructions <- arbitrary
+    verboseAssembly <- arbitrary
+    preserveComentsInAssembly <- arbitrary
+    return MachineCodeOptions { .. }
+
+instance Arbitrary DebugCompressionType where
+  arbitrary = elements [CompressNone, CompressGNU, CompressZ]
+
+arbitraryASCIIString :: Gen String
+#if MIN_VERSION_QuickCheck(2,10,0)
+arbitraryASCIIString = getASCIIString <$> arbitrary
+#else
+arbitraryASCIIString = arbitrary
+#endif
+
+instance Arbitrary CPUFeature where
+  arbitrary = CPUFeature . ByteString.pack <$>
+    suchThat arbitraryASCIIString (\s -> not (null s) && all isAlphaNum s)
+
+tests = testGroup "Target" [
+  testGroup "Options" [
+     testProperty "basic" $ \options -> ioProperty $ do
+       withTargetOptions $ \to -> do
+         pokeTargetOptions options to
+         options' <- peekTargetOptions to
+         return $ options === options',
+     testProperty "target machine" $ \options -> ioProperty $ do
+         withTargetOptions $ \to -> do
+           pokeTargetOptions options to
+           let triple = "i386-linux-gnu"
+               cpu = ""
+               features = mempty
+               reloc = Reloc.Default
+               codeModel = CodeModel.Default
+               codeGenOpt = CodeGenOpt.Default
+           (target, _) <- lookupTarget Nothing triple
+           withTargetMachine target triple cpu features to reloc codeModel codeGenOpt $ \tm -> do
+             options' <- peekTargetOptions =<< targetMachineOptions tm
+             return $ options === options'
+   ],
+  testGroup "LibraryFunction" [
+    testGroup "set-get" [
+       testCase (show lf) $ do
+         triple <- getDefaultTargetTriple
+         withTargetLibraryInfo triple $ \tli -> do
+           setLibraryFunctionAvailableWithName tli lf "foo"
+           nm <- getLibraryFunctionName tli lf
+           nm @?= "foo"
+       | lf <- [minBound, maxBound]
+     ],
+    testCase "get" $ do
+      triple <- getDefaultTargetTriple
+      withTargetLibraryInfo triple $ \tli -> do
+        lf <- getLibraryFunction tli "printf"
+        lf @?= Just LF__printf
+   ],
+  testCase "Host" $ do
+    features <- getHostCPUFeatures
+    return (),
+  testGroup "CPUFeature" [
+    testProperty "roundtrip" $ \cpuFeatures -> ioProperty $
+        withContext $ \context -> runEncodeAST context $ do
+          encodedFeatures :: CString <- (encodeM cpuFeatures)
+          decodedFeatures :: Map CPUFeature Bool <- liftIO $ runDecodeAST (decodeM encodedFeatures)
+          return (cpuFeatures == decodedFeatures)
+
+   ]
+ ]
diff --git a/test/LLVM/Test/Tests.hs b/test/LLVM/Test/Tests.hs
new file mode 100644
--- /dev/null
+++ b/test/LLVM/Test/Tests.hs
@@ -0,0 +1,54 @@
+module LLVM.Test.Tests where
+
+import Test.Tasty
+
+import qualified LLVM.Test.Analysis as Analysis
+import qualified LLVM.Test.Attribute as Attribute
+import qualified LLVM.Test.CallingConvention as CallingConvention
+import qualified LLVM.Test.Constants as Constants
+import qualified LLVM.Test.DataLayout as DataLayout
+import qualified LLVM.Test.ExecutionEngine as ExecutionEngine
+import qualified LLVM.Test.FunctionAttribute as FunctionAttribute
+import qualified LLVM.Test.Global as Global
+import qualified LLVM.Test.InlineAssembly as InlineAssembly
+import qualified LLVM.Test.Instructions as Instructions
+import qualified LLVM.Test.Instrumentation as Instrumentation
+import qualified LLVM.Test.Linking as Linking
+import qualified LLVM.Test.Metadata as Metadata
+import qualified LLVM.Test.Module as Module
+import qualified LLVM.Test.ObjectCode as ObjectCode
+import qualified LLVM.Test.Optimization as Optimization
+import qualified LLVM.Test.OrcJIT as OrcJIT
+import qualified LLVM.Test.ParameterAttribute as ParameterAttribute
+import qualified LLVM.Test.Target as Target
+import qualified LLVM.Test.Regression as Regression
+import qualified LLVM.Test.DataLayout as DataLayout
+import qualified LLVM.Test.IRBuilder as IRBuilder
+
+tests = testGroup "llvm-hs" [
+    CallingConvention.tests,
+    Constants.tests,
+    DataLayout.tests,
+    Attribute.tests,
+    FunctionAttribute.tests,
+    ExecutionEngine.tests,
+    Global.tests,
+    InlineAssembly.tests,
+    Instructions.tests,
+    Metadata.tests,
+    Module.tests,
+    OrcJIT.tests,
+    Optimization.tests,
+    ParameterAttribute.tests,
+    Target.tests,
+    Analysis.tests,
+    Linking.tests,
+    Instrumentation.tests,
+    ObjectCode.tests,
+    Regression.tests,
+  ( testGroup "llvm-hs-pure"
+  [ DataLayout.tests
+  , IRBuilder.tests
+  ])
+
+  ]
diff --git a/test/Test.hs b/test/Test.hs
new file mode 100644
--- /dev/null
+++ b/test/Test.hs
@@ -0,0 +1,6 @@
+import Test.Tasty
+import qualified LLVM.Test.Tests as LLVM
+import LLVM.CommandLine
+
+main :: IO ()
+main = defaultMain LLVM.tests
diff --git a/test/debug_metadata_1.ll b/test/debug_metadata_1.ll
new file mode 100644
--- /dev/null
+++ b/test/debug_metadata_1.ll
@@ -0,0 +1,50 @@
+declare !foo !0 !bar !{!"baz"} !qux !{!2} void @f1()
+
+define void @f2() !foo !0 !bar !{!"baz"} !qux !{!2} {
+  ret void
+}
+
+; --- [ Metadata definitions ] -------------------------------------------------
+
+; Empty named metadata definition.
+!foo = !{}
+
+; Plain named metadata definition.
+!bar = !{!0}
+
+; Multiple metadata IDs.
+!baz = !{!0, !1, !15}
+
+; !vars = !{!9, !10, !11}
+; Empty metadata definition.
+!0 = !{}
+
+; Plain metadata definition.
+!1 = !{!0}
+
+; Multiple metadata IDs.
+!2 = !{!0, !1}
+
+; Distinct.
+!3 = distinct !{!2}
+
+; Nested metadata.
+!4 = !{!{!{!0}}}
+
+; Metadata string.
+!5 = !{!"foo"}
+
+; Metadata constant.
+!6 = !{i32 42}
+
+; Metadata constant.
+!7 = !{!{!"bar"}}
+
+!15 = !{ !9, !10, !8, !11}
+
+!8 = distinct !DISubprogram(name: "foo", scope: !9)
+!9 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
+
+!10 = !DILexicalBlock(scope: !8, file: !9, line: 7, column: 35)
+
+!11 = !DINamespace(name: "Namespace", scope: !10)
diff --git a/test/debug_metadata_2.ll b/test/debug_metadata_2.ll
new file mode 100644
--- /dev/null
+++ b/test/debug_metadata_2.ll
@@ -0,0 +1,42 @@
+; ModuleID = 'test.c'
+source_filename = "test.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone sspstrong uwtable
+define i32 @f(i32) #0 !dbg !9 {
+  %2 = alloca i32, align 4
+  store i32 %0, i32* %2, align 4
+  call void @llvm.dbg.declare(metadata i32* %2, metadata !13, metadata !14), !dbg !15
+  %3 = load i32, i32* %2, align 4, !dbg !16
+  ret i32 %3, !dbg !17
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { noinline nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.1 (tags/RELEASE_501/final)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "test.c", directory: "/home/moritz/tmp")
+!2 = !{}
+!3 = !{i32 2, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{i32 7, !"PIE Level", i32 2}
+!8 = !{!"clang version 5.0.1 (tags/RELEASE_501/final)"}
+!9 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !10, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !DILocalVariable(name: "x", arg: 1, scope: !9, file: !1, line: 1, type: !12)
+!14 = !DIExpression()
+!15 = !DILocation(line: 1, column: 11, scope: !9)
+!16 = !DILocation(line: 2, column: 12, scope: !9)
+!17 = !DILocation(line: 2, column: 5, scope: !9)
diff --git a/test/debug_metadata_3.ll b/test/debug_metadata_3.ll
new file mode 100644
--- /dev/null
+++ b/test/debug_metadata_3.ll
@@ -0,0 +1,5759 @@
+; ModuleID = '/home/firefox/firefox/mozilla-unified/widget/LSBUtils.cpp'
+source_filename = "/home/firefox/firefox/mozilla-unified/widget/LSBUtils.cpp"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+%class.nsTSubstring = type { %"class.mozilla::detail::nsTStringRepr" }
+%"class.mozilla::detail::nsTStringRepr" = type { i8*, i32, i16, i16 }
+%"class.std::vector" = type { %"struct.std::_Vector_base" }
+%"struct.std::_Vector_base" = type { %"struct.std::_Vector_base<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >::_Vector_impl" }
+%"struct.std::_Vector_base<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >::_Vector_impl" = type { %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"* }
+%"class.std::__cxx11::basic_string" = type { %"struct.std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider", i64, %union.anon }
+%"struct.std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider" = type { i8* }
+%union.anon = type { i64, [8 x i8] }
+%"class.std::allocator.0" = type { i8 }
+%"struct.base::LaunchOptions" = type { i8, %"class.std::map", %"class.std::vector.6", %"class.mozilla::UniquePtr" }
+%"class.std::map" = type { %"class.std::_Rb_tree" }
+%"class.std::_Rb_tree" = type { %"struct.std::_Rb_tree<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >::_Rb_tree_impl" }
+%"struct.std::_Rb_tree<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >::_Rb_tree_impl" = type { %"struct.std::_Rb_tree_key_compare", %"struct.std::_Rb_tree_header" }
+%"struct.std::_Rb_tree_key_compare" = type { %"struct.std::less" }
+%"struct.std::less" = type { i8 }
+%"struct.std::_Rb_tree_header" = type { %"struct.std::_Rb_tree_node_base", i64 }
+%"struct.std::_Rb_tree_node_base" = type { i32, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"*, %"struct.std::_Rb_tree_node_base"* }
+%"class.std::vector.6" = type { %"struct.std::_Vector_base.7" }
+%"struct.std::_Vector_base.7" = type { %"struct.std::_Vector_base<std::pair<int, int>, std::allocator<std::pair<int, int> > >::_Vector_impl" }
+%"struct.std::_Vector_base<std::pair<int, int>, std::allocator<std::pair<int, int> > >::_Vector_impl" = type { %"struct.std::pair"*, %"struct.std::pair"*, %"struct.std::pair"* }
+%"struct.std::pair" = type { i32, i32 }
+%"class.mozilla::UniquePtr" = type { %"struct.mozilla::Pair" }
+%"struct.mozilla::Pair" = type { %"struct.mozilla::detail::PairHelper" }
+%"struct.mozilla::detail::PairHelper" = type { %"struct.base::LaunchOptions::ForkDelegate"* }
+%"struct.base::LaunchOptions::ForkDelegate" = type { i32 (...)** }
+%"class.std::allocator" = type { i8 }
+%"class.std::initializer_list" = type { %"class.std::__cxx11::basic_string"*, i64 }
+%"class.mozilla::DefaultDelete" = type { i8 }
+%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
+%struct._IO_marker = type opaque
+%struct._IO_codecvt = type opaque
+%struct._IO_wide_data = type opaque
+%"class.mozilla::Scoped" = type { %struct._IO_FILE* }
+%"struct.std::_Rb_tree_node" = type { %"struct.std::_Rb_tree_node_base", %"struct.__gnu_cxx::__aligned_membuf" }
+%"struct.__gnu_cxx::__aligned_membuf" = type { [64 x i8] }
+%"struct.std::pair.11" = type { %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string" }
+%"class.__gnu_cxx::new_allocator" = type { i8 }
+%"class.__gnu_cxx::__normal_iterator" = type { %"struct.std::pair"* }
+%"class.std::move_iterator" = type { %"struct.std::pair"* }
+%"class.std::allocator.8" = type { i8 }
+%"class.__gnu_cxx::new_allocator.9" = type { i8 }
+
+$_ZN4base13LaunchOptionsD2Ev = comdat any
+
+$_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev = comdat any
+
+$_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEED2Ev = comdat any
+
+$_ZNSt12_Vector_baseISt4pairIiiESaIS1_EED2Ev = comdat any
+
+$_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EED2Ev = comdat any
+
+$_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E = comdat any
+
+$_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_drop_nodeEPSt13_Rb_tree_nodeIS8_E = comdat any
+
+$_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_ED2Ev = comdat any
+
+$_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev = comdat any
+
+$_ZNSt12_Destroy_auxILb0EE9__destroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvT_S9_ = comdat any
+
+$_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_range_initializeIPKS5_EEvT_SB_St20forward_iterator_tag = comdat any
+
+$_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE11_M_allocateEm = comdat any
+
+$_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_m = comdat any
+
+$_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8allocateEmPKv = comdat any
+
+$_ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS7_EET0_T_SC_SB_ = comdat any
+
+$_ZNSt6vectorISt4pairIiiESaIS1_EE12emplace_backIJS1_EEEvDpOT_ = comdat any
+
+$_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_realloc_insertIJS1_EEEvN9__gnu_cxx17__normal_iteratorIPS1_S3_EEDpOT_ = comdat any
+
+$_ZNKSt6vectorISt4pairIiiESaIS1_EE12_M_check_lenEmPKc = comdat any
+
+$_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE11_M_allocateEm = comdat any
+
+$_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_m = comdat any
+
+$_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE8allocateEmPKv = comdat any
+
+$_ZN7mozilla21ScopedCloseFileTraits7releaseEP8_IO_FILE = comdat any
+
+@.str = private unnamed_addr constant [6 x i8] c"-idrc\00", align 1
+@.str.1 = private unnamed_addr constant [2 x i8] c"r\00", align 1
+@.str.2 = private unnamed_addr constant [85 x i8] c"Distributor ID:\09%255[^\0A]\0ADescription:\09%255[^\0A]\0ARelease:\09%255[^\0A]\0ACodename:\09%255[^\0A]\0A\00", align 1
+@.str.3 = private unnamed_addr constant [21 x i8] c"/usr/bin/lsb_release\00", align 1
+@.str.5 = private unnamed_addr constant [27 x i8] c"fatal: STL threw bad_alloc\00", align 1
+@.str.6 = private unnamed_addr constant [26 x i8] c"vector::_M_realloc_insert\00", align 1
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define hidden zeroext i1 @_ZN7mozilla6widget3lsb13GetLSBReleaseER12nsTSubstringIcES4_S4_S4_(%class.nsTSubstring* dereferenceable(16), %class.nsTSubstring* dereferenceable(16), %class.nsTSubstring* dereferenceable(16), %class.nsTSubstring* dereferenceable(16)) local_unnamed_addr #0 !dbg !2908 {
+  %5 = alloca [2 x i32], align 4
+  %6 = alloca %"class.std::vector", align 8
+  %7 = alloca [2 x %"class.std::__cxx11::basic_string"], align 8
+  %8 = alloca %"class.std::allocator.0", align 1
+  %9 = alloca %"class.std::allocator.0", align 1
+  %10 = alloca %"struct.base::LaunchOptions", align 8
+  %11 = alloca %"struct.std::pair", align 4
+  %12 = alloca i32, align 4
+  %13 = alloca [256 x i8], align 16
+  %14 = alloca [256 x i8], align 16
+  %15 = alloca [256 x i8], align 16
+  %16 = alloca [256 x i8], align 16
+  call void @llvm.dbg.value(metadata %class.nsTSubstring* %0, metadata !2915, metadata !DIExpression()), !dbg !3579
+  call void @llvm.dbg.value(metadata %class.nsTSubstring* %1, metadata !2916, metadata !DIExpression()), !dbg !3580
+  call void @llvm.dbg.value(metadata %class.nsTSubstring* %2, metadata !2917, metadata !DIExpression()), !dbg !3581
+  call void @llvm.dbg.value(metadata %class.nsTSubstring* %3, metadata !2918, metadata !DIExpression()), !dbg !3582
+  %17 = tail call i32 @access(i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), i32 4) #7, !dbg !3583
+  %18 = icmp eq i32 %17, 0, !dbg !3585
+  br i1 %18, label %19, label %85, !dbg !3586
+
+; <label>:19:                                     ; preds = %4
+  %20 = bitcast [2 x i32]* %5 to i8*, !dbg !3587
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %20) #8, !dbg !3587
+  call void @llvm.dbg.declare(metadata [2 x i32]* %5, metadata !2919, metadata !DIExpression()), !dbg !3588
+  %21 = getelementptr inbounds [2 x i32], [2 x i32]* %5, i64 0, i64 0, !dbg !3589
+  %22 = call i32 @pipe(i32* nonnull %21) #7, !dbg !3591
+  %23 = icmp eq i32 %22, -1, !dbg !3592
+  br i1 %23, label %83, label %24, !dbg !3593
+
+; <label>:24:                                     ; preds = %19
+  %25 = bitcast %"class.std::vector"* %6 to i8*, !dbg !3594
+  call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %25) #8, !dbg !3594
+  %26 = bitcast [2 x %"class.std::__cxx11::basic_string"]* %7 to i8*, !dbg !3595
+  call void @llvm.lifetime.start.p0i8(i64 64, i8* nonnull %26) #8, !dbg !3595
+  %27 = getelementptr inbounds [2 x %"class.std::__cxx11::basic_string"], [2 x %"class.std::__cxx11::basic_string"]* %7, i64 0, i64 0, !dbg !3595
+  %28 = getelementptr inbounds %"class.std::allocator.0", %"class.std::allocator.0"* %8, i64 0, i32 0, !dbg !3596
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %28) #8, !dbg !3596
+  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2EPKcRKS3_(%"class.std::__cxx11::basic_string"* nonnull %27, i8* getelementptr inbounds ([21 x i8], [21 x i8]* @.str.3, i64 0, i64 0), %"class.std::allocator.0"* nonnull dereferenceable(1) %8) #9, !dbg !3596
+  %29 = getelementptr inbounds [2 x %"class.std::__cxx11::basic_string"], [2 x %"class.std::__cxx11::basic_string"]* %7, i64 0, i64 1, !dbg !3595
+  %30 = getelementptr inbounds %"class.std::allocator.0", %"class.std::allocator.0"* %9, i64 0, i32 0, !dbg !3597
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %30) #8, !dbg !3597
+  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2EPKcRKS3_(%"class.std::__cxx11::basic_string"* nonnull %29, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0), %"class.std::allocator.0"* nonnull dereferenceable(1) %9) #9, !dbg !3597
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !2923, metadata !DIExpression(DW_OP_deref)), !dbg !3598
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !3599, metadata !DIExpression()) #8, !dbg !3605
+  call void @llvm.dbg.value(metadata %"class.std::allocator"* undef, metadata !3603, metadata !DIExpression()) #8, !dbg !3607
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !3608, metadata !DIExpression()) #8, !dbg !3613
+  call void @llvm.dbg.value(metadata %"class.std::allocator"* undef, metadata !3611, metadata !DIExpression()) #8, !dbg !3615
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !3616, metadata !DIExpression()) #8, !dbg !3621
+  call void @llvm.dbg.value(metadata %"class.std::allocator"* undef, metadata !3619, metadata !DIExpression()) #8, !dbg !3623
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %25, i8 0, i64 24, i1 false) #8, !dbg !3624
+  call void @llvm.dbg.value(metadata %"class.std::initializer_list"* undef, metadata !3602, metadata !DIExpression(DW_OP_deref)) #8, !dbg !3625
+  call void @llvm.dbg.value(metadata %"class.std::initializer_list"* undef, metadata !3602, metadata !DIExpression(DW_OP_deref)) #8, !dbg !3625
+  call void @llvm.dbg.value(metadata %"class.std::initializer_list"* undef, metadata !3626, metadata !DIExpression()) #8, !dbg !3630
+  %31 = getelementptr inbounds [2 x %"class.std::__cxx11::basic_string"], [2 x %"class.std::__cxx11::basic_string"]* %7, i64 0, i64 2, !dbg !3633
+  call void @_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_range_initializeIPKS5_EEvT_SB_St20forward_iterator_tag(%"class.std::vector"* nonnull %6, %"class.std::__cxx11::basic_string"* nonnull %27, %"class.std::__cxx11::basic_string"* nonnull %31) #7, !dbg !3634
+  br label %32, !dbg !3595
+
+; <label>:32:                                     ; preds = %32, %24
+  %33 = phi %"class.std::__cxx11::basic_string"* [ %31, %24 ], [ %34, %32 ], !dbg !3595
+  %34 = getelementptr inbounds %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %33, i64 -1, !dbg !3595
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %34, metadata !3635, metadata !DIExpression()) #8, !dbg !3642
+  call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(%"class.std::__cxx11::basic_string"* nonnull %34) #7, !dbg !3644
+  %35 = icmp eq %"class.std::__cxx11::basic_string"* %34, %27, !dbg !3595
+  br i1 %35, label %36, label %32, !dbg !3595
+
+; <label>:36:                                     ; preds = %32
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %30) #8, !dbg !3595
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %28) #8, !dbg !3595
+  call void @llvm.lifetime.end.p0i8(i64 64, i8* nonnull %26) #8, !dbg !3595
+  %37 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %10, i64 0, i32 0, !dbg !3646
+  call void @llvm.lifetime.start.p0i8(i64 88, i8* nonnull %37) #8, !dbg !3646
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3145, metadata !DIExpression(DW_OP_deref)), !dbg !3647
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3648, metadata !DIExpression()) #8, !dbg !3656
+  store i8 0, i8* %37, align 8, !dbg !3658
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3659, metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)) #8, !dbg !3663
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3665, metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)) #8, !dbg !3669
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3671, metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)) #8, !dbg !3675
+  %38 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %10, i64 0, i32 1, i32 0, i32 0, i32 0, i32 0, i32 0, !dbg !3677
+  %39 = getelementptr inbounds i8, i8* %38, i64 8, !dbg !3677
+  call void @llvm.dbg.value(metadata i8* %39, metadata !3678, metadata !DIExpression()) #8, !dbg !3682
+  %40 = bitcast i8* %39 to i32*, !dbg !3684
+  store i32 0, i32* %40, align 8, !dbg !3686
+  call void @llvm.dbg.value(metadata i8* %39, metadata !3687, metadata !DIExpression()) #8, !dbg !3690
+  %41 = getelementptr inbounds i8, i8* %38, i64 16, !dbg !3692
+  %42 = bitcast i8* %41 to %"struct.std::_Rb_tree_node_base"**, !dbg !3692
+  store %"struct.std::_Rb_tree_node_base"* null, %"struct.std::_Rb_tree_node_base"** %42, align 8, !dbg !3693
+  %43 = getelementptr inbounds i8, i8* %38, i64 24, !dbg !3694
+  %44 = bitcast i8* %43 to i8**, !dbg !3695
+  store i8* %39, i8** %44, align 8, !dbg !3695
+  %45 = getelementptr inbounds i8, i8* %38, i64 32, !dbg !3696
+  %46 = bitcast i8* %45 to i8**, !dbg !3697
+  store i8* %39, i8** %46, align 8, !dbg !3697
+  %47 = getelementptr inbounds i8, i8* %38, i64 40, !dbg !3698
+  %48 = bitcast i8* %47 to i64*, !dbg !3698
+  store i64 0, i64* %48, align 8, !dbg !3699
+  %49 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %10, i64 0, i32 2, !dbg !3700
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3701, metadata !DIExpression(DW_OP_plus_uconst, 80, DW_OP_stack_value)) #8, !dbg !3706
+  call void @llvm.dbg.value(metadata i8* null, metadata !3704, metadata !DIExpression()) #8, !dbg !3708
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3709, metadata !DIExpression(DW_OP_plus_uconst, 80, DW_OP_stack_value)) #8, !dbg !3723
+  call void @llvm.dbg.value(metadata %"class.mozilla::DefaultDelete"* undef, metadata !3721, metadata !DIExpression()) #8, !dbg !3725
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3726, metadata !DIExpression(DW_OP_plus_uconst, 80, DW_OP_stack_value)) #8, !dbg !3735
+  %50 = bitcast %"class.std::vector.6"* %49 to i8*, !dbg !3700
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 8 %50, i8 0, i64 32, i1 false) #8, !dbg !3737
+  %51 = bitcast %"struct.std::pair"* %11 to i8*, !dbg !3738
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %51) #8, !dbg !3738
+  %52 = getelementptr inbounds [2 x i32], [2 x i32]* %5, i64 0, i64 1, !dbg !3739
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %11, metadata !3740, metadata !DIExpression()), !dbg !3752
+  call void @llvm.dbg.value(metadata i32* %52, metadata !3750, metadata !DIExpression()), !dbg !3754
+  %53 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %11, i64 0, i32 0, !dbg !3755
+  %54 = load i32, i32* %52, align 4, !dbg !3756
+  store i32 %54, i32* %53, align 4, !dbg !3755
+  %55 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %11, i64 0, i32 1, !dbg !3757
+  store i32 1, i32* %55, align 4, !dbg !3757
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %49, metadata !3758, metadata !DIExpression()) #8, !dbg !3763
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %11, metadata !3761, metadata !DIExpression()) #8, !dbg !3765
+  call void @_ZNSt6vectorISt4pairIiiESaIS1_EE12emplace_backIJS1_EEEvDpOT_(%"class.std::vector.6"* nonnull %49, %"struct.std::pair"* nonnull dereferenceable(8) %11) #7, !dbg !3766
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %51) #8, !dbg !3767
+  store i8 1, i8* %37, align 8, !dbg !3768
+  %56 = bitcast i32* %12 to i8*, !dbg !3769
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %56) #8, !dbg !3769
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !2923, metadata !DIExpression(DW_OP_deref)), !dbg !3598
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3145, metadata !DIExpression(DW_OP_deref)), !dbg !3647
+  call void @llvm.dbg.value(metadata i32* %12, metadata !3499, metadata !DIExpression(DW_OP_deref)), !dbg !3770
+  %57 = call zeroext i1 @_ZN4base9LaunchAppERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS6_EERKNS_13LaunchOptionsEPi(%"class.std::vector"* nonnull dereferenceable(24) %6, %"struct.base::LaunchOptions"* nonnull dereferenceable(88) %10, i32* nonnull %12) #7, !dbg !3771
+  %58 = load i32, i32* %52, align 4, !dbg !3772
+  %59 = call i32 @close(i32 %58) #7, !dbg !3773
+  %60 = load i32, i32* %21, align 4, !dbg !3774
+  br i1 %57, label %63, label %61, !dbg !3777
+
+; <label>:61:                                     ; preds = %36
+  %62 = call i32 @close(i32 %60) #7, !dbg !3778
+  br label %81, !dbg !3779
+
+; <label>:63:                                     ; preds = %36
+  %64 = call %struct._IO_FILE* @fdopen(i32 %60, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) #7, !dbg !3780
+  call void @llvm.dbg.value(metadata %"class.mozilla::Scoped"* undef, metadata !3506, metadata !DIExpression(DW_OP_deref)), !dbg !3781
+  call void @llvm.dbg.value(metadata %"class.mozilla::Scoped"* undef, metadata !3506, metadata !DIExpression(DW_OP_deref)), !dbg !3781
+  %65 = icmp eq %struct._IO_FILE* %64, null, !dbg !3782
+  br i1 %65, label %66, label %69, !dbg !3784
+
+; <label>:66:                                     ; preds = %63
+  %67 = load i32, i32* %21, align 4, !dbg !3785
+  %68 = call i32 @close(i32 %67) #7, !dbg !3787
+  br label %79, !dbg !3788
+
+; <label>:69:                                     ; preds = %63
+  %70 = getelementptr inbounds [256 x i8], [256 x i8]* %13, i64 0, i64 0, !dbg !3789
+  call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %70) #8, !dbg !3789
+  call void @llvm.dbg.declare(metadata [256 x i8]* %13, metadata !3572, metadata !DIExpression()), !dbg !3790
+  %71 = getelementptr inbounds [256 x i8], [256 x i8]* %14, i64 0, i64 0, !dbg !3789
+  call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %71) #8, !dbg !3789
+  call void @llvm.dbg.declare(metadata [256 x i8]* %14, metadata !3576, metadata !DIExpression()), !dbg !3791
+  %72 = getelementptr inbounds [256 x i8], [256 x i8]* %15, i64 0, i64 0, !dbg !3789
+  call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %72) #8, !dbg !3789
+  call void @llvm.dbg.declare(metadata [256 x i8]* %15, metadata !3577, metadata !DIExpression()), !dbg !3792
+  %73 = getelementptr inbounds [256 x i8], [256 x i8]* %16, i64 0, i64 0, !dbg !3789
+  call void @llvm.lifetime.start.p0i8(i64 256, i8* nonnull %73) #8, !dbg !3789
+  call void @llvm.dbg.declare(metadata [256 x i8]* %16, metadata !3578, metadata !DIExpression()), !dbg !3793
+  call void @llvm.dbg.value(metadata %"class.mozilla::Scoped"* undef, metadata !3506, metadata !DIExpression(DW_OP_deref)), !dbg !3781
+  %74 = call i32 (%struct._IO_FILE*, i8*, ...) @fscanf(%struct._IO_FILE* nonnull %64, i8* getelementptr inbounds ([85 x i8], [85 x i8]* @.str.2, i64 0, i64 0), i8* nonnull %70, i8* nonnull %71, i8* nonnull %72, i8* nonnull %73) #9, !dbg !3794
+  %75 = icmp eq i32 %74, 4, !dbg !3796
+  br i1 %75, label %76, label %77, !dbg !3797
+
+; <label>:76:                                     ; preds = %69
+  call void @_ZN12nsTSubstringIcE6AssignEPKcj(%class.nsTSubstring* nonnull %0, i8* nonnull %70, i32 -1) #7, !dbg !3798
+  call void @_ZN12nsTSubstringIcE6AssignEPKcj(%class.nsTSubstring* nonnull %1, i8* nonnull %71, i32 -1) #7, !dbg !3799
+  call void @_ZN12nsTSubstringIcE6AssignEPKcj(%class.nsTSubstring* nonnull %2, i8* nonnull %72, i32 -1) #7, !dbg !3800
+  call void @_ZN12nsTSubstringIcE6AssignEPKcj(%class.nsTSubstring* nonnull %3, i8* nonnull %73, i32 -1) #7, !dbg !3801
+  br label %77, !dbg !3802
+
+; <label>:77:                                     ; preds = %69, %76
+  %78 = phi i1 [ true, %76 ], [ false, %69 ], !dbg !3803
+  call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %73) #8, !dbg !3804
+  call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %72) #8, !dbg !3804
+  call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %71) #8, !dbg !3804
+  call void @llvm.lifetime.end.p0i8(i64 256, i8* nonnull %70) #8, !dbg !3804
+  br label %79
+
+; <label>:79:                                     ; preds = %77, %66
+  %80 = phi i1 [ %78, %77 ], [ false, %66 ], !dbg !3805
+  call void @llvm.dbg.value(metadata %"class.mozilla::Scoped"* undef, metadata !3506, metadata !DIExpression(DW_OP_deref)), !dbg !3781
+  call void @llvm.dbg.value(metadata %"class.mozilla::Scoped"* undef, metadata !3806, metadata !DIExpression()) #8, !dbg !3810
+  call void @_ZN7mozilla21ScopedCloseFileTraits7releaseEP8_IO_FILE(%struct._IO_FILE* %64) #7, !dbg !3812
+  br label %81
+
+; <label>:81:                                     ; preds = %79, %61
+  %82 = phi i1 [ %80, %79 ], [ false, %61 ], !dbg !3774
+  call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %56) #8, !dbg !3804
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %10, metadata !3145, metadata !DIExpression(DW_OP_deref)), !dbg !3647
+  call void @_ZN4base13LaunchOptionsD2Ev(%"struct.base::LaunchOptions"* nonnull %10) #7, !dbg !3804
+  call void @llvm.lifetime.end.p0i8(i64 88, i8* nonnull %37) #8, !dbg !3804
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %6, metadata !2923, metadata !DIExpression(DW_OP_deref)), !dbg !3598
+  call void @_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev(%"class.std::vector"* nonnull %6) #7, !dbg !3804
+  call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %25) #8, !dbg !3804
+  br label %83
+
+; <label>:83:                                     ; preds = %19, %81
+  %84 = phi i1 [ %82, %81 ], [ false, %19 ], !dbg !3814
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %20) #8, !dbg !3804
+  br label %85
+
+; <label>:85:                                     ; preds = %4, %83
+  %86 = phi i1 [ %84, %83 ], [ false, %4 ], !dbg !3816
+  ret i1 %86, !dbg !3804
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: minsize nounwind optsize
+declare i32 @access(i8* nocapture readonly, i32) local_unnamed_addr #2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #3
+
+; Function Attrs: minsize nounwind optsize
+declare i32 @pipe(i32*) local_unnamed_addr #2
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+declare void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2EPKcRKS3_(%"class.std::__cxx11::basic_string"*, i8*, %"class.std::allocator.0"* dereferenceable(1)) unnamed_addr #0 align 2
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #3
+
+; Function Attrs: minsize optsize
+declare hidden zeroext i1 @_ZN4base9LaunchAppERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS6_EERKNS_13LaunchOptionsEPi(%"class.std::vector"* dereferenceable(24), %"struct.base::LaunchOptions"* dereferenceable(88), i32*) local_unnamed_addr #4
+
+; Function Attrs: minsize optsize
+declare i32 @close(i32) local_unnamed_addr #4
+
+; Function Attrs: minsize nounwind optsize
+declare noalias %struct._IO_FILE* @fdopen(i32, i8* nocapture readonly) local_unnamed_addr #2
+
+; Function Attrs: minsize nounwind optsize
+declare i32 @fscanf(%struct._IO_FILE* nocapture, i8* nocapture readonly, ...) local_unnamed_addr #2
+
+; Function Attrs: minsize optsize
+declare hidden void @_ZN12nsTSubstringIcE6AssignEPKcj(%class.nsTSubstring*, i8*, i32) local_unnamed_addr #4
+
+; Function Attrs: inlinehint minsize nounwind optsize sspstrong uwtable
+define linkonce_odr hidden void @_ZN4base13LaunchOptionsD2Ev(%"struct.base::LaunchOptions"*) unnamed_addr #5 comdat align 2 !dbg !3818 {
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %0, metadata !3821, metadata !DIExpression()), !dbg !3822
+  %2 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %0, i64 0, i32 3, !dbg !3823
+  tail call void @_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEED2Ev(%"class.mozilla::UniquePtr"* nonnull %2) #7, !dbg !3823
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %0, metadata !3825, metadata !DIExpression(DW_OP_plus_uconst, 56, DW_OP_stack_value)) #8, !dbg !3828
+  %3 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %0, i64 0, i32 2, i32 0, !dbg !3830
+  tail call void @_ZNSt12_Vector_baseISt4pairIiiESaIS1_EED2Ev(%"struct.std::_Vector_base.7"* nonnull %3) #7, !dbg !3832
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions"* %0, metadata !3833, metadata !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)) #8, !dbg !3836
+  %4 = getelementptr inbounds %"struct.base::LaunchOptions", %"struct.base::LaunchOptions"* %0, i64 0, i32 1, i32 0, !dbg !3838
+  tail call void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EED2Ev(%"class.std::_Rb_tree"* nonnull %4) #7, !dbg !3838
+  ret void, !dbg !3840
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev(%"class.std::vector"*) unnamed_addr #0 comdat align 2 !dbg !3841 {
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %0, metadata !3843, metadata !DIExpression()), !dbg !3844
+  %2 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, !dbg !3845
+  %3 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, i32 0, i32 0, !dbg !3847
+  %4 = load %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"** %3, align 8, !dbg !3847
+  %5 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, i32 0, i32 1, !dbg !3848
+  %6 = load %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"** %5, align 8, !dbg !3848
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %4, metadata !3849, metadata !DIExpression()) #8, !dbg !3859
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !3855, metadata !DIExpression()) #8, !dbg !3861
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %2, metadata !3856, metadata !DIExpression()) #8, !dbg !3862
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %4, metadata !3863, metadata !DIExpression()) #8, !dbg !3870
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !3868, metadata !DIExpression()) #8, !dbg !3872
+  tail call void @_ZNSt12_Destroy_auxILb0EE9__destroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvT_S9_(%"class.std::__cxx11::basic_string"* %4, %"class.std::__cxx11::basic_string"* %6) #7, !dbg !3873
+  tail call void @_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev(%"struct.std::_Vector_base"* %2) #7, !dbg !3874
+  ret void, !dbg !3875
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr hidden void @_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEED2Ev(%"class.mozilla::UniquePtr"*) unnamed_addr #0 comdat align 2 !dbg !3876 {
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3878, metadata !DIExpression()), !dbg !3879
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3880, metadata !DIExpression()) #8, !dbg !3885
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions::ForkDelegate"* null, metadata !3883, metadata !DIExpression()) #8, !dbg !3888
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3889, metadata !DIExpression()) #8, !dbg !3892
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3894, metadata !DIExpression()) #8, !dbg !3897
+  %2 = getelementptr inbounds %"class.mozilla::UniquePtr", %"class.mozilla::UniquePtr"* %0, i64 0, i32 0, i32 0, i32 0, !dbg !3899
+  %3 = load %"struct.base::LaunchOptions::ForkDelegate"*, %"struct.base::LaunchOptions::ForkDelegate"** %2, align 8, !dbg !3900
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions::ForkDelegate"* %3, metadata !3884, metadata !DIExpression()) #8, !dbg !3901
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3889, metadata !DIExpression()) #8, !dbg !3902
+  call void @llvm.dbg.value(metadata %"class.mozilla::UniquePtr"* %0, metadata !3894, metadata !DIExpression()) #8, !dbg !3904
+  store %"struct.base::LaunchOptions::ForkDelegate"* null, %"struct.base::LaunchOptions::ForkDelegate"** %2, align 8, !dbg !3906
+  %4 = icmp eq %"struct.base::LaunchOptions::ForkDelegate"* %3, null, !dbg !3907
+  br i1 %4, label %10, label %5, !dbg !3909
+
+; <label>:5:                                      ; preds = %1
+  call void @llvm.dbg.value(metadata %"struct.base::LaunchOptions::ForkDelegate"* %3, metadata !3910, metadata !DIExpression()) #8, !dbg !3915
+  %6 = bitcast %"struct.base::LaunchOptions::ForkDelegate"* %3 to void (%"struct.base::LaunchOptions::ForkDelegate"*)***, !dbg !3918
+  %7 = load void (%"struct.base::LaunchOptions::ForkDelegate"*)**, void (%"struct.base::LaunchOptions::ForkDelegate"*)*** %6, align 8, !dbg !3918
+  %8 = getelementptr inbounds void (%"struct.base::LaunchOptions::ForkDelegate"*)*, void (%"struct.base::LaunchOptions::ForkDelegate"*)** %7, i64 1, !dbg !3918
+  %9 = load void (%"struct.base::LaunchOptions::ForkDelegate"*)*, void (%"struct.base::LaunchOptions::ForkDelegate"*)** %8, align 8, !dbg !3918
+  tail call void %9(%"struct.base::LaunchOptions::ForkDelegate"* nonnull %3) #7, !dbg !3918
+  br label %10, !dbg !3919
+
+; <label>:10:                                     ; preds = %1, %5
+  ret void, !dbg !3920
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt12_Vector_baseISt4pairIiiESaIS1_EED2Ev(%"struct.std::_Vector_base.7"*) unnamed_addr #0 comdat align 2 !dbg !3921 {
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %0, metadata !3923, metadata !DIExpression()), !dbg !3925
+  %2 = getelementptr inbounds %"struct.std::_Vector_base.7", %"struct.std::_Vector_base.7"* %0, i64 0, i32 0, i32 0, !dbg !3926
+  %3 = load %"struct.std::pair"*, %"struct.std::pair"** %2, align 8, !dbg !3926
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %0, metadata !3928, metadata !DIExpression()) #8, !dbg !3933
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %3, metadata !3931, metadata !DIExpression()) #8, !dbg !3935
+  %4 = icmp eq %"struct.std::pair"* %3, null, !dbg !3936
+  br i1 %4, label %7, label %5, !dbg !3938
+
+; <label>:5:                                      ; preds = %1
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %0, metadata !3939, metadata !DIExpression()) #8, !dbg !3944
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %3, metadata !3942, metadata !DIExpression()) #8, !dbg !3946
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %0, metadata !3947, metadata !DIExpression()) #8, !dbg !3953
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %3, metadata !3950, metadata !DIExpression()) #8, !dbg !3955
+  %6 = bitcast %"struct.std::pair"* %3 to i8*, !dbg !3956
+  call void @llvm.dbg.value(metadata i8* %6, metadata !3957, metadata !DIExpression()) #8, !dbg !3961
+  tail call void @free(i8* %6) #7, !dbg !3963
+  br label %7, !dbg !3964
+
+; <label>:7:                                      ; preds = %1, %5
+  ret void, !dbg !3965
+}
+
+; Function Attrs: minsize nounwind optsize
+declare void @free(i8* nocapture) local_unnamed_addr #2
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EED2Ev(%"class.std::_Rb_tree"*) unnamed_addr #0 comdat align 2 !dbg !3966 {
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !3968, metadata !DIExpression()), !dbg !3969
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !3970, metadata !DIExpression()), !dbg !3973
+  %2 = getelementptr inbounds %"class.std::_Rb_tree", %"class.std::_Rb_tree"* %0, i64 0, i32 0, i32 0, i32 0, i32 0, !dbg !3976
+  %3 = getelementptr inbounds i8, i8* %2, i64 16, !dbg !3977
+  %4 = bitcast i8* %3 to %"struct.std::_Rb_tree_node"**, !dbg !3977
+  %5 = load %"struct.std::_Rb_tree_node"*, %"struct.std::_Rb_tree_node"** %4, align 8, !dbg !3977
+  tail call void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E(%"class.std::_Rb_tree"* %0, %"struct.std::_Rb_tree_node"* %5) #9, !dbg !3978
+  ret void, !dbg !3979
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E(%"class.std::_Rb_tree"*, %"struct.std::_Rb_tree_node"*) local_unnamed_addr #0 comdat align 2 !dbg !3980 {
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !3982, metadata !DIExpression()), !dbg !3986
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !3983, metadata !DIExpression()), !dbg !3987
+  br label %3, !dbg !3988
+
+; <label>:3:                                      ; preds = %6, %2
+  %4 = phi %"struct.std::_Rb_tree_node"* [ %1, %2 ], [ %12, %6 ]
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %4, metadata !3983, metadata !DIExpression()), !dbg !3987
+  %5 = icmp eq %"struct.std::_Rb_tree_node"* %4, null, !dbg !3989
+  br i1 %5, label %13, label %6, !dbg !3988
+
+; <label>:6:                                      ; preds = %3
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %4, metadata !3990, metadata !DIExpression()), !dbg !3993
+  %7 = getelementptr inbounds %"struct.std::_Rb_tree_node", %"struct.std::_Rb_tree_node"* %4, i64 0, i32 0, i32 3, !dbg !3995
+  %8 = bitcast %"struct.std::_Rb_tree_node_base"** %7 to %"struct.std::_Rb_tree_node"**, !dbg !3995
+  %9 = load %"struct.std::_Rb_tree_node"*, %"struct.std::_Rb_tree_node"** %8, align 8, !dbg !3995
+  tail call void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E(%"class.std::_Rb_tree"* %0, %"struct.std::_Rb_tree_node"* %9) #9, !dbg !3996
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %4, metadata !3997, metadata !DIExpression()), !dbg !4000
+  %10 = getelementptr inbounds %"struct.std::_Rb_tree_node", %"struct.std::_Rb_tree_node"* %4, i64 0, i32 0, i32 2, !dbg !4002
+  %11 = bitcast %"struct.std::_Rb_tree_node_base"** %10 to %"struct.std::_Rb_tree_node"**, !dbg !4002
+  %12 = load %"struct.std::_Rb_tree_node"*, %"struct.std::_Rb_tree_node"** %11, align 8, !dbg !4002
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %12, metadata !3984, metadata !DIExpression()), !dbg !4003
+  tail call void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_drop_nodeEPSt13_Rb_tree_nodeIS8_E(%"class.std::_Rb_tree"* %0, %"struct.std::_Rb_tree_node"* nonnull %4) #7, !dbg !4004
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %12, metadata !3983, metadata !DIExpression()), !dbg !3987
+  br label %3, !dbg !3988, !llvm.loop !4005
+
+; <label>:13:                                     ; preds = %3
+  ret void, !dbg !4007
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_drop_nodeEPSt13_Rb_tree_nodeIS8_E(%"class.std::_Rb_tree"*, %"struct.std::_Rb_tree_node"*) local_unnamed_addr #0 comdat align 2 !dbg !4008 {
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4010, metadata !DIExpression()), !dbg !4012
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4011, metadata !DIExpression()), !dbg !4013
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4014, metadata !DIExpression()) #8, !dbg !4018
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4017, metadata !DIExpression()) #8, !dbg !4020
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4021, metadata !DIExpression()) #8, !dbg !4024
+  %3 = getelementptr inbounds %"struct.std::_Rb_tree_node", %"struct.std::_Rb_tree_node"* %1, i64 0, i32 1, !dbg !4026
+  call void @llvm.dbg.value(metadata %"struct.__gnu_cxx::__aligned_membuf"* %3, metadata !4027, metadata !DIExpression()) #8, !dbg !4031
+  %4 = bitcast %"struct.__gnu_cxx::__aligned_membuf"* %3 to %"struct.std::pair.11"*, !dbg !4033
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4034, metadata !DIExpression()) #8, !dbg !4068
+  call void @llvm.dbg.value(metadata %"struct.std::pair.11"* %4, metadata !4067, metadata !DIExpression()) #8, !dbg !4070
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4071, metadata !DIExpression()) #8, !dbg !4079
+  call void @llvm.dbg.value(metadata %"struct.std::pair.11"* %4, metadata !4077, metadata !DIExpression()) #8, !dbg !4081
+  tail call void @_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_ED2Ev(%"struct.std::pair.11"* nonnull %4) #7, !dbg !4082
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4083, metadata !DIExpression()) #8, !dbg !4087
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4086, metadata !DIExpression()) #8, !dbg !4089
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4090, metadata !DIExpression()) #8, !dbg !4095
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4093, metadata !DIExpression()) #8, !dbg !4097
+  call void @llvm.dbg.value(metadata i64 1, metadata !4094, metadata !DIExpression()) #8, !dbg !4098
+  call void @llvm.dbg.value(metadata %"class.std::_Rb_tree"* %0, metadata !4099, metadata !DIExpression()) #8, !dbg !4104
+  call void @llvm.dbg.value(metadata %"struct.std::_Rb_tree_node"* %1, metadata !4102, metadata !DIExpression()) #8, !dbg !4106
+  call void @llvm.dbg.value(metadata i64 1, metadata !4103, metadata !DIExpression()) #8, !dbg !4107
+  %5 = bitcast %"struct.std::_Rb_tree_node"* %1 to i8*, !dbg !4108
+  call void @llvm.dbg.value(metadata i8* %5, metadata !3957, metadata !DIExpression()) #8, !dbg !4109
+  tail call void @free(i8* %5) #7, !dbg !4111
+  ret void, !dbg !4112
+}
+
+; Function Attrs: inlinehint minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_ED2Ev(%"struct.std::pair.11"*) unnamed_addr #5 comdat align 2 !dbg !4113 {
+  call void @llvm.dbg.value(metadata %"struct.std::pair.11"* %0, metadata !4118, metadata !DIExpression()), !dbg !4119
+  %2 = getelementptr inbounds %"struct.std::pair.11", %"struct.std::pair.11"* %0, i64 0, i32 1, !dbg !4120
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !3635, metadata !DIExpression()) #8, !dbg !4122
+  tail call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(%"class.std::__cxx11::basic_string"* nonnull %2) #7, !dbg !4124
+  %3 = getelementptr inbounds %"struct.std::pair.11", %"struct.std::pair.11"* %0, i64 0, i32 0, !dbg !4120
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %3, metadata !3635, metadata !DIExpression()) #8, !dbg !4125
+  tail call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(%"class.std::__cxx11::basic_string"* %3) #7, !dbg !4127
+  ret void, !dbg !4128
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+declare void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(%"class.std::__cxx11::basic_string"*) local_unnamed_addr #0 align 2
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev(%"struct.std::_Vector_base"*) unnamed_addr #0 comdat align 2 !dbg !4129 {
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %0, metadata !4131, metadata !DIExpression()), !dbg !4132
+  %2 = getelementptr inbounds %"struct.std::_Vector_base", %"struct.std::_Vector_base"* %0, i64 0, i32 0, i32 0, !dbg !4133
+  %3 = load %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"** %2, align 8, !dbg !4133
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %0, metadata !4135, metadata !DIExpression()) #8, !dbg !4140
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %3, metadata !4138, metadata !DIExpression()) #8, !dbg !4142
+  %4 = icmp eq %"class.std::__cxx11::basic_string"* %3, null, !dbg !4143
+  br i1 %4, label %7, label %5, !dbg !4145
+
+; <label>:5:                                      ; preds = %1
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %0, metadata !4146, metadata !DIExpression()) #8, !dbg !4151
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %3, metadata !4149, metadata !DIExpression()) #8, !dbg !4153
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %0, metadata !4154, metadata !DIExpression()) #8, !dbg !4160
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %3, metadata !4157, metadata !DIExpression()) #8, !dbg !4162
+  %6 = bitcast %"class.std::__cxx11::basic_string"* %3 to i8*, !dbg !4163
+  call void @llvm.dbg.value(metadata i8* %6, metadata !3957, metadata !DIExpression()) #8, !dbg !4164
+  tail call void @free(i8* %6) #7, !dbg !4166
+  br label %7, !dbg !4167
+
+; <label>:7:                                      ; preds = %1, %5
+  ret void, !dbg !4168
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt12_Destroy_auxILb0EE9__destroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvT_S9_(%"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"*) local_unnamed_addr #0 comdat align 2 !dbg !4169 {
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %0, metadata !4174, metadata !DIExpression()), !dbg !4176
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4175, metadata !DIExpression()), !dbg !4177
+  br label %3, !dbg !4178
+
+; <label>:3:                                      ; preds = %6, %2
+  %4 = phi %"class.std::__cxx11::basic_string"* [ %0, %2 ], [ %7, %6 ]
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %4, metadata !4174, metadata !DIExpression()), !dbg !4176
+  %5 = icmp eq %"class.std::__cxx11::basic_string"* %4, %1, !dbg !4179
+  br i1 %5, label %8, label %6, !dbg !4182
+
+; <label>:6:                                      ; preds = %3
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %4, metadata !4183, metadata !DIExpression()) #8, !dbg !4188
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %4, metadata !3635, metadata !DIExpression()) #8, !dbg !4190
+  tail call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv(%"class.std::__cxx11::basic_string"* %4) #7, !dbg !4192
+  %7 = getelementptr inbounds %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %4, i64 1, !dbg !4193
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %7, metadata !4174, metadata !DIExpression()), !dbg !4176
+  br label %3, !dbg !4194, !llvm.loop !4195
+
+; <label>:8:                                      ; preds = %3
+  ret void, !dbg !4197
+}
+
+; Function Attrs: minsize noreturn optsize
+declare extern_weak void @mozalloc_abort(i8*) local_unnamed_addr #6
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_range_initializeIPKS5_EEvT_SB_St20forward_iterator_tag(%"class.std::vector"*, %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"*) local_unnamed_addr #0 comdat align 2 !dbg !4198 {
+  call void @llvm.dbg.value(metadata %"class.std::vector"* %0, metadata !4209, metadata !DIExpression()), !dbg !4215
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4210, metadata !DIExpression()), !dbg !4216
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4211, metadata !DIExpression()), !dbg !4217
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4218, metadata !DIExpression()), !dbg !4231
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4228, metadata !DIExpression()), !dbg !4233
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4234, metadata !DIExpression()), !dbg !4249
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4245, metadata !DIExpression()), !dbg !4251
+  %4 = ptrtoint %"class.std::__cxx11::basic_string"* %2 to i64, !dbg !4252
+  %5 = ptrtoint %"class.std::__cxx11::basic_string"* %1 to i64, !dbg !4252
+  %6 = sub i64 %4, %5, !dbg !4252
+  %7 = ashr exact i64 %6, 5, !dbg !4252
+  call void @llvm.dbg.value(metadata i64 %7, metadata !4213, metadata !DIExpression()), !dbg !4253
+  %8 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, !dbg !4254
+  %9 = tail call %"class.std::__cxx11::basic_string"* @_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE11_M_allocateEm(%"struct.std::_Vector_base"* %8, i64 %7) #9, !dbg !4254
+  %10 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, i32 0, i32 0, !dbg !4255
+  store %"class.std::__cxx11::basic_string"* %9, %"class.std::__cxx11::basic_string"** %10, align 8, !dbg !4256
+  %11 = getelementptr inbounds %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %9, i64 %7, !dbg !4257
+  %12 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, i32 0, i32 2, !dbg !4258
+  store %"class.std::__cxx11::basic_string"* %11, %"class.std::__cxx11::basic_string"** %12, align 8, !dbg !4259
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4260, metadata !DIExpression()) #8, !dbg !4270
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4266, metadata !DIExpression()) #8, !dbg !4272
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %9, metadata !4267, metadata !DIExpression()) #8, !dbg !4273
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4274, metadata !DIExpression()) #8, !dbg !4283
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4279, metadata !DIExpression()) #8, !dbg !4285
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %9, metadata !4280, metadata !DIExpression()) #8, !dbg !4286
+  call void @llvm.dbg.value(metadata i8 1, metadata !4281, metadata !DIExpression()) #8, !dbg !4287
+  %13 = tail call %"class.std::__cxx11::basic_string"* @_ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS7_EET0_T_SC_SB_(%"class.std::__cxx11::basic_string"* %1, %"class.std::__cxx11::basic_string"* %2, %"class.std::__cxx11::basic_string"* %9) #7, !dbg !4288
+  %14 = getelementptr inbounds %"class.std::vector", %"class.std::vector"* %0, i64 0, i32 0, i32 0, i32 1, !dbg !4289
+  store %"class.std::__cxx11::basic_string"* %13, %"class.std::__cxx11::basic_string"** %14, align 8, !dbg !4290
+  ret void, !dbg !4291
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"class.std::__cxx11::basic_string"* @_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE11_M_allocateEm(%"struct.std::_Vector_base"*, i64) local_unnamed_addr #0 comdat align 2 !dbg !4292 {
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base"* %0, metadata !4294, metadata !DIExpression()), !dbg !4296
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4295, metadata !DIExpression()), !dbg !4297
+  %3 = icmp eq i64 %1, 0, !dbg !4298
+  br i1 %3, label %7, label %4, !dbg !4299
+
+; <label>:4:                                      ; preds = %2
+  %5 = bitcast %"struct.std::_Vector_base"* %0 to %"class.std::allocator"*, !dbg !4300
+  %6 = tail call %"class.std::__cxx11::basic_string"* @_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_m(%"class.std::allocator"* dereferenceable(1) %5, i64 %1) #9, !dbg !4301
+  br label %7, !dbg !4299
+
+; <label>:7:                                      ; preds = %2, %4
+  %8 = phi %"class.std::__cxx11::basic_string"* [ %6, %4 ], [ null, %2 ], !dbg !4299
+  ret %"class.std::__cxx11::basic_string"* %8, !dbg !4302
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"class.std::__cxx11::basic_string"* @_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_m(%"class.std::allocator"* dereferenceable(1), i64) local_unnamed_addr #0 comdat align 2 !dbg !4303 {
+  call void @llvm.dbg.value(metadata %"class.std::allocator"* %0, metadata !4305, metadata !DIExpression()), !dbg !4307
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4306, metadata !DIExpression()), !dbg !4308
+  %3 = bitcast %"class.std::allocator"* %0 to %"class.__gnu_cxx::new_allocator"*, !dbg !4309
+  %4 = tail call %"class.std::__cxx11::basic_string"* @_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8allocateEmPKv(%"class.__gnu_cxx::new_allocator"* nonnull %3, i64 %1, i8* null) #9, !dbg !4310
+  ret %"class.std::__cxx11::basic_string"* %4, !dbg !4311
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"class.std::__cxx11::basic_string"* @_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8allocateEmPKv(%"class.__gnu_cxx::new_allocator"*, i64, i8*) local_unnamed_addr #0 comdat align 2 !dbg !4312 {
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::new_allocator"* %0, metadata !4314, metadata !DIExpression()), !dbg !4317
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4315, metadata !DIExpression()), !dbg !4318
+  call void @llvm.dbg.value(metadata i8* %2, metadata !4316, metadata !DIExpression()), !dbg !4319
+  %4 = icmp ugt i64 %1, 576460752303423487, !dbg !4320
+  br i1 %4, label %5, label %6, !dbg !4322
+
+; <label>:5:                                      ; preds = %3
+  tail call void @mozalloc_abort(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.5, i64 0, i64 0)) #10, !dbg !4323
+  unreachable, !dbg !4323
+
+; <label>:6:                                      ; preds = %3
+  %7 = shl i64 %1, 5, !dbg !4327
+  call void @llvm.dbg.value(metadata i64 %7, metadata !4328, metadata !DIExpression()) #8, !dbg !4331
+  %8 = tail call noalias i8* @moz_xmalloc(i64 %7) #7, !dbg !4333
+  %9 = bitcast i8* %8 to %"class.std::__cxx11::basic_string"*, !dbg !4334
+  ret %"class.std::__cxx11::basic_string"* %9, !dbg !4335
+}
+
+; Function Attrs: minsize optsize
+declare extern_weak noalias i8* @moz_xmalloc(i64) local_unnamed_addr #4
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"class.std::__cxx11::basic_string"* @_ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS7_EET0_T_SC_SB_(%"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"*) local_unnamed_addr #0 comdat align 2 !dbg !4336 {
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %0, metadata !4342, metadata !DIExpression()), !dbg !4346
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %1, metadata !4343, metadata !DIExpression()), !dbg !4347
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4344, metadata !DIExpression()), !dbg !4348
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %2, metadata !4345, metadata !DIExpression()), !dbg !4349
+  br label %4, !dbg !4350
+
+; <label>:4:                                      ; preds = %8, %3
+  %5 = phi %"class.std::__cxx11::basic_string"* [ %0, %3 ], [ %9, %8 ]
+  %6 = phi %"class.std::__cxx11::basic_string"* [ %2, %3 ], [ %10, %8 ], !dbg !4353
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %5, metadata !4342, metadata !DIExpression()), !dbg !4346
+  %7 = icmp eq %"class.std::__cxx11::basic_string"* %5, %1, !dbg !4356
+  br i1 %7, label %11, label %8, !dbg !4357
+
+; <label>:8:                                      ; preds = %4
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4358, metadata !DIExpression()) #8, !dbg !4369
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %5, metadata !4363, metadata !DIExpression()) #8, !dbg !4371
+  tail call void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2ERKS4_(%"class.std::__cxx11::basic_string"* %6, %"class.std::__cxx11::basic_string"* nonnull dereferenceable(32) %5) #7, !dbg !4372
+  %9 = getelementptr inbounds %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %5, i64 1, !dbg !4373
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %9, metadata !4342, metadata !DIExpression()), !dbg !4346
+  %10 = getelementptr inbounds %"class.std::__cxx11::basic_string", %"class.std::__cxx11::basic_string"* %6, i64 1, !dbg !4374
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %10, metadata !4345, metadata !DIExpression()), !dbg !4349
+  br label %4, !dbg !4375, !llvm.loop !4376
+
+; <label>:11:                                     ; preds = %4
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  call void @llvm.dbg.value(metadata %"class.std::__cxx11::basic_string"* %6, metadata !4345, metadata !DIExpression()), !dbg !4349
+  ret %"class.std::__cxx11::basic_string"* %6, !dbg !4378
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+declare void @_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2ERKS4_(%"class.std::__cxx11::basic_string"*, %"class.std::__cxx11::basic_string"* dereferenceable(32)) unnamed_addr #0 align 2
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt6vectorISt4pairIiiESaIS1_EE12emplace_backIJS1_EEEvDpOT_(%"class.std::vector.6"*, %"struct.std::pair"* dereferenceable(8)) local_unnamed_addr #0 comdat align 2 !dbg !4379 {
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4388, metadata !DIExpression()), !dbg !4390
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4389, metadata !DIExpression()), !dbg !4391
+  %3 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 1, !dbg !4392
+  %4 = load %"struct.std::pair"*, %"struct.std::pair"** %3, align 8, !dbg !4392
+  %5 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 2, !dbg !4394
+  %6 = load %"struct.std::pair"*, %"struct.std::pair"** %5, align 8, !dbg !4394
+  %7 = icmp eq %"struct.std::pair"* %4, %6, !dbg !4395
+  br i1 %7, label %14, label %8, !dbg !4396
+
+; <label>:8:                                      ; preds = %2
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4397, metadata !DIExpression()), !dbg !4407
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %4, metadata !4405, metadata !DIExpression()), !dbg !4410
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4406, metadata !DIExpression()), !dbg !4411
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4412, metadata !DIExpression()), !dbg !4420
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %4, metadata !4418, metadata !DIExpression()), !dbg !4422
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4419, metadata !DIExpression()), !dbg !4423
+  %9 = bitcast %"struct.std::pair"* %1 to i64*, !dbg !4424
+  %10 = bitcast %"struct.std::pair"* %4 to i64*, !dbg !4424
+  %11 = load i64, i64* %9, align 4, !dbg !4424
+  store i64 %11, i64* %10, align 4, !dbg !4424
+  %12 = load %"struct.std::pair"*, %"struct.std::pair"** %3, align 8, !dbg !4425
+  %13 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %12, i64 1, !dbg !4425
+  store %"struct.std::pair"* %13, %"struct.std::pair"** %3, align 8, !dbg !4425
+  br label %15, !dbg !4426
+
+; <label>:14:                                     ; preds = %2
+  tail call void @_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_realloc_insertIJS1_EEEvN9__gnu_cxx17__normal_iteratorIPS1_S3_EEDpOT_(%"class.std::vector.6"* nonnull %0, %"struct.std::pair"* %4, %"struct.std::pair"* nonnull dereferenceable(8) %1) #9, !dbg !4427
+  br label %15
+
+; <label>:15:                                     ; preds = %14, %8
+  ret void, !dbg !4428
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr void @_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_realloc_insertIJS1_EEEvN9__gnu_cxx17__normal_iteratorIPS1_S3_EEDpOT_(%"class.std::vector.6"*, %"struct.std::pair"*, %"struct.std::pair"* dereferenceable(8)) local_unnamed_addr #0 comdat align 2 !dbg !4429 {
+  %4 = ptrtoint %"struct.std::pair"* %1 to i64
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4434, metadata !DIExpression()), !dbg !4443
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %2, metadata !4436, metadata !DIExpression()), !dbg !4444
+  %5 = tail call i64 @_ZNKSt6vectorISt4pairIiiESaIS1_EE12_M_check_lenEmPKc(%"class.std::vector.6"* %0, i64 1, i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str.6, i64 0, i64 0)) #9, !dbg !4445
+  call void @llvm.dbg.value(metadata i64 %5, metadata !4437, metadata !DIExpression()), !dbg !4446
+  %6 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, !dbg !4447
+  %7 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 0, !dbg !4448
+  %8 = load %"struct.std::pair"*, %"struct.std::pair"** %7, align 8, !dbg !4448
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !4438, metadata !DIExpression()), !dbg !4449
+  %9 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 1, !dbg !4450
+  %10 = load %"struct.std::pair"*, %"struct.std::pair"** %9, align 8, !dbg !4450
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %10, metadata !4439, metadata !DIExpression()), !dbg !4451
+  %11 = ptrtoint %"struct.std::pair"* %8 to i64, !dbg !4452
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::__normal_iterator"* undef, metadata !4435, metadata !DIExpression(DW_OP_deref)), !dbg !4453
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::__normal_iterator"* undef, metadata !4454, metadata !DIExpression()), !dbg !4461
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::__normal_iterator"* undef, metadata !4460, metadata !DIExpression()), !dbg !4463
+  %12 = sub i64 %4, %11, !dbg !4464
+  %13 = ashr exact i64 %12, 3, !dbg !4464
+  call void @llvm.dbg.value(metadata i64 %13, metadata !4440, metadata !DIExpression()), !dbg !4465
+  %14 = tail call %"struct.std::pair"* @_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE11_M_allocateEm(%"struct.std::_Vector_base.7"* %6, i64 %5) #9, !dbg !4466
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4441, metadata !DIExpression()), !dbg !4467
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4442, metadata !DIExpression()), !dbg !4468
+  %15 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %14, i64 %13, !dbg !4469
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4397, metadata !DIExpression()), !dbg !4472
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %15, metadata !4405, metadata !DIExpression()), !dbg !4474
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %2, metadata !4406, metadata !DIExpression()), !dbg !4475
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4412, metadata !DIExpression()), !dbg !4476
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %15, metadata !4418, metadata !DIExpression()), !dbg !4478
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %2, metadata !4419, metadata !DIExpression()), !dbg !4479
+  %16 = bitcast %"struct.std::pair"* %2 to i64*, !dbg !4480
+  %17 = bitcast %"struct.std::pair"* %15 to i64*, !dbg !4480
+  %18 = load i64, i64* %16, align 4, !dbg !4480
+  store i64 %18, i64* %17, align 4, !dbg !4480
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* null, metadata !4442, metadata !DIExpression()), !dbg !4468
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::__normal_iterator"* undef, metadata !4435, metadata !DIExpression(DW_OP_deref)), !dbg !4453
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !4481, metadata !DIExpression()), !dbg !4493
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4486, metadata !DIExpression()), !dbg !4495
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4487, metadata !DIExpression()), !dbg !4496
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !4497, metadata !DIExpression()), !dbg !4507
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4502, metadata !DIExpression()), !dbg !4509
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4503, metadata !DIExpression()), !dbg !4510
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !4511, metadata !DIExpression()), !dbg !4520
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4516, metadata !DIExpression()), !dbg !4522
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4517, metadata !DIExpression()), !dbg !4523
+  call void @llvm.dbg.value(metadata i8 1, metadata !4518, metadata !DIExpression()), !dbg !4524
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4525, metadata !DIExpression()), !dbg !4532
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %14, metadata !4531, metadata !DIExpression()), !dbg !4534
+  br label %19, !dbg !4535
+
+; <label>:19:                                     ; preds = %23, %3
+  %20 = phi %"struct.std::pair"* [ %8, %3 ], [ %27, %23 ]
+  %21 = phi %"struct.std::pair"* [ %14, %3 ], [ %28, %23 ], !dbg !4538
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %21, metadata !4531, metadata !DIExpression()), !dbg !4534
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4541
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4530, metadata !DIExpression(DW_OP_deref)), !dbg !4542
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4543, metadata !DIExpression()), !dbg !4550
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4549, metadata !DIExpression()), !dbg !4552
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4553, metadata !DIExpression()), !dbg !4557
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4556, metadata !DIExpression()), !dbg !4559
+  %22 = icmp eq %"struct.std::pair"* %20, %1, !dbg !4560
+  br i1 %22, label %29, label %23, !dbg !4561
+
+; <label>:23:                                     ; preds = %19
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4541
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %21, metadata !4562, metadata !DIExpression()), !dbg !4570
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %20, metadata !4567, metadata !DIExpression()), !dbg !4572
+  %24 = bitcast %"struct.std::pair"* %20 to i64*, !dbg !4573
+  %25 = bitcast %"struct.std::pair"* %21 to i64*, !dbg !4573
+  %26 = load i64, i64* %24, align 4, !dbg !4573
+  store i64 %26, i64* %25, align 4, !dbg !4573
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4541
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4574, metadata !DIExpression()), !dbg !4578
+  %27 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %20, i64 1, !dbg !4580
+  %28 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %21, i64 1, !dbg !4581
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %28, metadata !4531, metadata !DIExpression()), !dbg !4534
+  br label %19, !dbg !4582
+
+; <label>:29:                                     ; preds = %19
+  %30 = lshr i64 %12, 3, !dbg !4535
+  %31 = getelementptr %"struct.std::pair", %"struct.std::pair"* %14, i64 %30, !dbg !4535
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %31, metadata !4531, metadata !DIExpression()), !dbg !4534
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %21, metadata !4531, metadata !DIExpression()), !dbg !4534
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %31, metadata !4442, metadata !DIExpression()), !dbg !4468
+  %32 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %31, i64 1, !dbg !4586
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4442, metadata !DIExpression()), !dbg !4468
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::__normal_iterator"* undef, metadata !4435, metadata !DIExpression(DW_OP_deref)), !dbg !4453
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4481, metadata !DIExpression()), !dbg !4587
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %10, metadata !4486, metadata !DIExpression()), !dbg !4589
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4487, metadata !DIExpression()), !dbg !4590
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4497, metadata !DIExpression()), !dbg !4591
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %10, metadata !4502, metadata !DIExpression()), !dbg !4593
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4503, metadata !DIExpression()), !dbg !4594
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %1, metadata !4511, metadata !DIExpression()), !dbg !4595
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %10, metadata !4516, metadata !DIExpression()), !dbg !4597
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4517, metadata !DIExpression()), !dbg !4598
+  call void @llvm.dbg.value(metadata i8 1, metadata !4518, metadata !DIExpression()), !dbg !4599
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4525, metadata !DIExpression()), !dbg !4600
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %32, metadata !4531, metadata !DIExpression()), !dbg !4602
+  br label %33, !dbg !4603
+
+; <label>:33:                                     ; preds = %37, %29
+  %34 = phi %"struct.std::pair"* [ %1, %29 ], [ %41, %37 ]
+  %35 = phi %"struct.std::pair"* [ %32, %29 ], [ %42, %37 ], !dbg !4604
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %35, metadata !4531, metadata !DIExpression()), !dbg !4602
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4605
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4530, metadata !DIExpression(DW_OP_deref)), !dbg !4606
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4543, metadata !DIExpression()), !dbg !4607
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4549, metadata !DIExpression()), !dbg !4609
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4553, metadata !DIExpression()), !dbg !4610
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4556, metadata !DIExpression()), !dbg !4612
+  %36 = icmp eq %"struct.std::pair"* %34, %10, !dbg !4613
+  br i1 %36, label %43, label %37, !dbg !4614
+
+; <label>:37:                                     ; preds = %33
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4605
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %35, metadata !4562, metadata !DIExpression()), !dbg !4615
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %34, metadata !4567, metadata !DIExpression()), !dbg !4617
+  %38 = bitcast %"struct.std::pair"* %34 to i64*, !dbg !4618
+  %39 = bitcast %"struct.std::pair"* %35 to i64*, !dbg !4618
+  %40 = load i64, i64* %38, align 4, !dbg !4618
+  store i64 %40, i64* %39, align 4, !dbg !4618
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4529, metadata !DIExpression(DW_OP_deref)), !dbg !4605
+  call void @llvm.dbg.value(metadata %"class.std::move_iterator"* undef, metadata !4574, metadata !DIExpression()), !dbg !4619
+  %41 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %34, i64 1, !dbg !4621
+  %42 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %35, i64 1, !dbg !4622
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %42, metadata !4531, metadata !DIExpression()), !dbg !4602
+  br label %33, !dbg !4623
+
+; <label>:43:                                     ; preds = %33
+  %44 = ptrtoint %"struct.std::pair"* %10 to i64, !dbg !4603
+  %45 = sub i64 %44, %4, !dbg !4603
+  %46 = lshr i64 %45, 3, !dbg !4603
+  %47 = getelementptr %"struct.std::pair", %"struct.std::pair"* %32, i64 %46, !dbg !4603
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %47, metadata !4531, metadata !DIExpression()), !dbg !4602
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %35, metadata !4531, metadata !DIExpression()), !dbg !4602
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %47, metadata !4442, metadata !DIExpression()), !dbg !4468
+  %48 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 2, !dbg !4624
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %6, metadata !3928, metadata !DIExpression()) #8, !dbg !4625
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !3931, metadata !DIExpression()) #8, !dbg !4627
+  %49 = icmp eq %"struct.std::pair"* %8, null, !dbg !4628
+  br i1 %49, label %52, label %50, !dbg !4629
+
+; <label>:50:                                     ; preds = %43
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %6, metadata !3939, metadata !DIExpression()) #8, !dbg !4630
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !3942, metadata !DIExpression()) #8, !dbg !4632
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %6, metadata !3947, metadata !DIExpression()) #8, !dbg !4633
+  call void @llvm.dbg.value(metadata %"struct.std::pair"* %8, metadata !3950, metadata !DIExpression()) #8, !dbg !4635
+  %51 = bitcast %"struct.std::pair"* %8 to i8*, !dbg !4636
+  call void @llvm.dbg.value(metadata i8* %51, metadata !3957, metadata !DIExpression()) #8, !dbg !4637
+  tail call void @free(i8* %51) #7, !dbg !4639
+  br label %52, !dbg !4640
+
+; <label>:52:                                     ; preds = %43, %50
+  store %"struct.std::pair"* %14, %"struct.std::pair"** %7, align 8, !dbg !4641
+  store %"struct.std::pair"* %47, %"struct.std::pair"** %9, align 8, !dbg !4642
+  %53 = getelementptr inbounds %"struct.std::pair", %"struct.std::pair"* %14, i64 %5, !dbg !4643
+  store %"struct.std::pair"* %53, %"struct.std::pair"** %48, align 8, !dbg !4644
+  ret void, !dbg !4645
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr i64 @_ZNKSt6vectorISt4pairIiiESaIS1_EE12_M_check_lenEmPKc(%"class.std::vector.6"*, i64, i8*) local_unnamed_addr #0 comdat align 2 !dbg !4646 {
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4648, metadata !DIExpression()), !dbg !4653
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4650, metadata !DIExpression()), !dbg !4654
+  call void @llvm.dbg.value(metadata i8* %2, metadata !4651, metadata !DIExpression()), !dbg !4655
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4656, metadata !DIExpression()), !dbg !4659
+  %4 = getelementptr inbounds %"class.std::vector.6", %"class.std::vector.6"* %0, i64 0, i32 0, i32 0, i32 1, !dbg !4662
+  %5 = bitcast %"struct.std::pair"** %4 to i64*, !dbg !4662
+  %6 = load i64, i64* %5, align 8, !dbg !4662
+  %7 = bitcast %"class.std::vector.6"* %0 to i64*, !dbg !4663
+  %8 = load i64, i64* %7, align 8, !dbg !4663
+  %9 = sub i64 %6, %8, !dbg !4664
+  %10 = ashr exact i64 %9, 3, !dbg !4664
+  %11 = sub nsw i64 2305843009213693951, %10, !dbg !4665
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4650, metadata !DIExpression()), !dbg !4654
+  %12 = icmp ult i64 %11, %1, !dbg !4666
+  br i1 %12, label %13, label %14, !dbg !4667
+
+; <label>:13:                                     ; preds = %3
+  call void @llvm.dbg.value(metadata i8* %2, metadata !4668, metadata !DIExpression()) #8, !dbg !4671
+  tail call void @mozalloc_abort(i8* %2) #10, !dbg !4673
+  unreachable, !dbg !4673
+
+; <label>:14:                                     ; preds = %3
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4656, metadata !DIExpression()), !dbg !4674
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4656, metadata !DIExpression()), !dbg !4676
+  %15 = icmp ult i64 %10, %1, !dbg !4678
+  %16 = select i1 %15, i64 %1, i64 %10, !dbg !4693
+  %17 = add i64 %16, %10, !dbg !4694
+  call void @llvm.dbg.value(metadata i64 %17, metadata !4652, metadata !DIExpression()), !dbg !4695
+  call void @llvm.dbg.value(metadata %"class.std::vector.6"* %0, metadata !4656, metadata !DIExpression()), !dbg !4696
+  %18 = icmp ult i64 %17, %10, !dbg !4698
+  %19 = icmp ugt i64 %17, 2305843009213693951, !dbg !4699
+  %20 = or i1 %18, %19, !dbg !4700
+  %21 = select i1 %20, i64 2305843009213693951, i64 %17, !dbg !4700
+  ret i64 %21, !dbg !4701
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"struct.std::pair"* @_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE11_M_allocateEm(%"struct.std::_Vector_base.7"*, i64) local_unnamed_addr #0 comdat align 2 !dbg !4702 {
+  call void @llvm.dbg.value(metadata %"struct.std::_Vector_base.7"* %0, metadata !4704, metadata !DIExpression()), !dbg !4706
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4705, metadata !DIExpression()), !dbg !4707
+  %3 = icmp eq i64 %1, 0, !dbg !4708
+  br i1 %3, label %7, label %4, !dbg !4709
+
+; <label>:4:                                      ; preds = %2
+  %5 = bitcast %"struct.std::_Vector_base.7"* %0 to %"class.std::allocator.8"*, !dbg !4710
+  %6 = tail call %"struct.std::pair"* @_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_m(%"class.std::allocator.8"* dereferenceable(1) %5, i64 %1) #9, !dbg !4711
+  br label %7, !dbg !4709
+
+; <label>:7:                                      ; preds = %2, %4
+  %8 = phi %"struct.std::pair"* [ %6, %4 ], [ null, %2 ], !dbg !4709
+  ret %"struct.std::pair"* %8, !dbg !4712
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"struct.std::pair"* @_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_m(%"class.std::allocator.8"* dereferenceable(1), i64) local_unnamed_addr #0 comdat align 2 !dbg !4713 {
+  call void @llvm.dbg.value(metadata %"class.std::allocator.8"* %0, metadata !4715, metadata !DIExpression()), !dbg !4717
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4716, metadata !DIExpression()), !dbg !4718
+  %3 = bitcast %"class.std::allocator.8"* %0 to %"class.__gnu_cxx::new_allocator.9"*, !dbg !4719
+  %4 = tail call %"struct.std::pair"* @_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE8allocateEmPKv(%"class.__gnu_cxx::new_allocator.9"* nonnull %3, i64 %1, i8* null) #9, !dbg !4720
+  ret %"struct.std::pair"* %4, !dbg !4721
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr %"struct.std::pair"* @_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE8allocateEmPKv(%"class.__gnu_cxx::new_allocator.9"*, i64, i8*) local_unnamed_addr #0 comdat align 2 !dbg !4722 {
+  call void @llvm.dbg.value(metadata %"class.__gnu_cxx::new_allocator.9"* %0, metadata !4724, metadata !DIExpression()), !dbg !4727
+  call void @llvm.dbg.value(metadata i64 %1, metadata !4725, metadata !DIExpression()), !dbg !4728
+  call void @llvm.dbg.value(metadata i8* %2, metadata !4726, metadata !DIExpression()), !dbg !4729
+  %4 = icmp ugt i64 %1, 2305843009213693951, !dbg !4730
+  br i1 %4, label %5, label %6, !dbg !4732
+
+; <label>:5:                                      ; preds = %3
+  tail call void @mozalloc_abort(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.5, i64 0, i64 0)) #10, !dbg !4733
+  unreachable, !dbg !4733
+
+; <label>:6:                                      ; preds = %3
+  %7 = shl i64 %1, 3, !dbg !4735
+  call void @llvm.dbg.value(metadata i64 %7, metadata !4328, metadata !DIExpression()) #8, !dbg !4736
+  %8 = tail call noalias i8* @moz_xmalloc(i64 %7) #7, !dbg !4738
+  %9 = bitcast i8* %8 to %"struct.std::pair"*, !dbg !4739
+  ret %"struct.std::pair"* %9, !dbg !4740
+}
+
+; Function Attrs: minsize nounwind optsize sspstrong uwtable
+define linkonce_odr hidden void @_ZN7mozilla21ScopedCloseFileTraits7releaseEP8_IO_FILE(%struct._IO_FILE*) local_unnamed_addr #0 comdat align 2 !dbg !4741 {
+  call void @llvm.dbg.value(metadata %struct._IO_FILE* %0, metadata !4743, metadata !DIExpression()), !dbg !4744
+  %2 = icmp eq %struct._IO_FILE* %0, null, !dbg !4745
+  br i1 %2, label %5, label %3, !dbg !4747
+
+; <label>:3:                                      ; preds = %1
+  %4 = tail call i32 @fclose(%struct._IO_FILE* nonnull %0) #9, !dbg !4748
+  br label %5, !dbg !4750
+
+; <label>:5:                                      ; preds = %1, %3
+  ret void, !dbg !4751
+}
+
+; Function Attrs: minsize nounwind optsize
+declare i32 @fclose(%struct._IO_FILE* nocapture) local_unnamed_addr #2
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+; Function Attrs: argmemonly nounwind
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #3
+
+attributes #0 = { minsize nounwind optsize sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+attributes #2 = { minsize nounwind optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { argmemonly nounwind }
+attributes #4 = { minsize optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #5 = { inlinehint minsize nounwind optsize sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #6 = { minsize noreturn optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #7 = { minsize nounwind optsize }
+attributes #8 = { nounwind }
+attributes #9 = { minsize optsize }
+attributes #10 = { minsize noreturn nounwind optsize }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2903, !2904, !2905, !2906}
+!llvm.ident = !{!2907}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 7.0.0 (tags/RELEASE_700/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !36, globals: !1567, imports: !1572)
+!1 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/widget/LSBUtils.cpp", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2 = !{!3, !11, !17, !24, !29}
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "_Lock_policy", scope: !5, file: !4, line: 49, baseType: !6, size: 32, elements: !7, identifier: "_ZTSN9__gnu_cxx12_Lock_policyE")
+!4 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/ext/concurrence.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!5 = !DINamespace(name: "__gnu_cxx", scope: null)
+!6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
+!7 = !{!8, !9, !10}
+!8 = !DIEnumerator(name: "_S_single", value: 0, isUnsigned: true)
+!9 = !DIEnumerator(name: "_S_mutex", value: 1, isUnsigned: true)
+!10 = !DIEnumerator(name: "_S_atomic", value: 2, isUnsigned: true)
+!11 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "_Rb_tree_color", scope: !13, file: !12, line: 99, baseType: !6, size: 32, elements: !14, identifier: "_ZTSSt14_Rb_tree_color")
+!12 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_tree.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!13 = !DINamespace(name: "std", scope: null)
+!14 = !{!15, !16}
+!15 = !DIEnumerator(name: "_S_red", value: 0, isUnsigned: true)
+!16 = !DIEnumerator(name: "_S_black", value: 1, isUnsigned: true)
+!17 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "StorageType", scope: !19, file: !18, line: 20, baseType: !6, size: 32, elements: !21, identifier: "_ZTSN7mozilla6detail11StorageTypeE")
+!18 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/Pair.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!19 = !DINamespace(name: "detail", scope: !20)
+!20 = !DINamespace(name: "mozilla", scope: null)
+!21 = !{!22, !23}
+!22 = !DIEnumerator(name: "AsBase", value: 0, isUnsigned: true)
+!23 = !DIEnumerator(name: "AsMember", value: 1, isUnsigned: true)
+!24 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Voidness", scope: !19, file: !25, line: 882, baseType: !6, size: 32, elements: !26, identifier: "_ZTSN7mozilla6detail8VoidnessE")
+!25 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/TypeTraits.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!26 = !{!27, !28}
+!27 = !DIEnumerator(name: "TIsVoid", value: 0, isUnsigned: true)
+!28 = !DIEnumerator(name: "TIsNotVoid", value: 1, isUnsigned: true)
+!29 = !DICompositeType(tag: DW_TAG_enumeration_type, scope: !31, file: !30, line: 158, baseType: !6, size: 32, elements: !34, identifier: "_ZTSNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEUt_E")
+!30 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/basic_string.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!31 = !DICompositeType(tag: DW_TAG_class_type, name: "basic_string<char, std::char_traits<char>, std::allocator<char> >", scope: !33, file: !32, line: 1607, flags: DIFlagFwdDecl, identifier: "_ZTSNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE")
+!32 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/basic_string.tcc", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!33 = !DINamespace(name: "__cxx11", scope: !13, exportSymbols: true)
+!34 = !{!35}
+!35 = !DIEnumerator(name: "_S_local_capacity", value: 15, isUnsigned: true)
+!36 = !{!37, !47, !302, !321, !506, !988, !1159, !1208, !178, !1008, !175, !1260, !1261, !1262, !70, !1518, !31, !951}
+!37 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !39, file: !38, line: 319, baseType: !40)
+!38 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/nsTSubstring.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!39 = !DICompositeType(tag: DW_TAG_class_type, name: "nsTSubstring<char>", file: !38, line: 1350, flags: DIFlagFwdDecl, identifier: "_ZTS12nsTSubstringIcE")
+!40 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !42, file: !41, line: 120, baseType: !43)
+!41 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/nsTStringRepr.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!42 = !DICompositeType(tag: DW_TAG_class_type, name: "nsTStringRepr<char>", scope: !19, file: !41, line: 304, flags: DIFlagFwdDecl, identifier: "_ZTSN7mozilla6detail13nsTStringReprIcEE")
+!43 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint32_t", file: !44, line: 26, baseType: !45)
+!44 = !DIFile(filename: "/usr/include/bits/stdint-uintn.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!45 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint32_t", file: !46, line: 41, baseType: !6)
+!46 = !DIFile(filename: "/usr/include/bits/types.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!47 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64)
+!48 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Tp_alloc_type", scope: !50, file: !49, line: 84, baseType: !299)
+!49 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_vector.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!50 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Vector_base<std::pair<int, int>, std::allocator<std::pair<int, int> > >", scope: !13, file: !49, line: 81, size: 192, flags: DIFlagTypePassByReference, elements: !51, templateParams: !298, identifier: "_ZTSSt12_Vector_baseISt4pairIiiESaIS1_EE")
+!51 = !{!52, !252, !257, !262, !266, !269, !274, !277, !280, !283, !287, !290, !291, !294, !297}
+!52 = !DIDerivedType(tag: DW_TAG_member, name: "_M_impl", scope: !50, file: !49, line: 290, baseType: !53, size: 192)
+!53 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Vector_impl", scope: !50, file: !49, line: 88, size: 192, flags: DIFlagTypePassByReference, elements: !54, identifier: "_ZTSNSt12_Vector_baseISt4pairIiiESaIS1_EE12_Vector_implE")
+!54 = !{!55, !56, !233, !234, !235, !239, !244, !248}
+!55 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !53, baseType: !48, extraData: i32 0)
+!56 = !DIDerivedType(tag: DW_TAG_member, name: "_M_start", scope: !53, file: !49, line: 91, baseType: !57, size: 64)
+!57 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !50, file: !49, line: 86, baseType: !58)
+!58 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !60, file: !59, line: 59, baseType: !69)
+!59 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/ext/alloc_traits.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!60 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__alloc_traits<std::allocator<std::pair<int, int> >, std::pair<int, int> >", scope: !5, file: !59, line: 50, size: 8, flags: DIFlagTypePassByValue, elements: !61, templateParams: !231, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_EE")
+!61 = !{!62, !217, !220, !224, !227, !228, !229, !230}
+!62 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !60, baseType: !63, extraData: i32 0)
+!63 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "allocator_traits<std::allocator<std::pair<int, int> > >", scope: !13, file: !64, line: 384, size: 8, flags: DIFlagTypePassByValue, elements: !65, templateParams: !215, identifier: "_ZTSSt16allocator_traitsISaISt4pairIiiEEE")
+!64 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/alloc_traits.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!65 = !{!66, !199, !203, !206, !212}
+!66 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_m", scope: !63, file: !64, line: 435, type: !67, isLocal: false, isDefinition: false, scopeLine: 435, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!67 = !DISubroutineType(types: !68)
+!68 = !{!69, !138, !198}
+!69 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !63, file: !64, line: 392, baseType: !70)
+!70 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !71, size: 64)
+!71 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "pair<int, int>", scope: !13, file: !72, line: 208, size: 64, flags: DIFlagTypePassByValue, elements: !73, templateParams: !135, identifier: "_ZTSSt4pairIiiE")
+!72 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_pair.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!73 = !{!74, !95, !96, !97, !103, !107, !123, !132}
+!74 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !71, baseType: !75, flags: DIFlagPrivate, extraData: i32 0)
+!75 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "__pair_base<int, int>", scope: !13, file: !72, line: 190, size: 8, flags: DIFlagTypePassByValue, elements: !76, templateParams: !91, identifier: "_ZTSSt11__pair_baseIiiE")
+!76 = !{!77, !81, !82, !87}
+!77 = !DISubprogram(name: "__pair_base", scope: !75, file: !72, line: 194, type: !78, isLocal: false, isDefinition: false, scopeLine: 194, flags: DIFlagPrototyped, isOptimized: true)
+!78 = !DISubroutineType(types: !79)
+!79 = !{null, !80}
+!80 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !75, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!81 = !DISubprogram(name: "~__pair_base", scope: !75, file: !72, line: 195, type: !78, isLocal: false, isDefinition: false, scopeLine: 195, flags: DIFlagPrototyped, isOptimized: true)
+!82 = !DISubprogram(name: "__pair_base", scope: !75, file: !72, line: 196, type: !83, isLocal: false, isDefinition: false, scopeLine: 196, flags: DIFlagPrototyped, isOptimized: true)
+!83 = !DISubroutineType(types: !84)
+!84 = !{null, !80, !85}
+!85 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !86, size: 64)
+!86 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !75)
+!87 = !DISubprogram(name: "operator=", linkageName: "_ZNSt11__pair_baseIiiEaSERKS0_", scope: !75, file: !72, line: 197, type: !88, isLocal: false, isDefinition: false, scopeLine: 197, flags: DIFlagPrototyped, isOptimized: true)
+!88 = !DISubroutineType(types: !89)
+!89 = !{!90, !80, !85}
+!90 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !75, size: 64)
+!91 = !{!92, !94}
+!92 = !DITemplateTypeParameter(name: "_U1", type: !93)
+!93 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!94 = !DITemplateTypeParameter(name: "_U2", type: !93)
+!95 = !DIDerivedType(tag: DW_TAG_member, name: "first", scope: !71, file: !72, line: 214, baseType: !93, size: 32)
+!96 = !DIDerivedType(tag: DW_TAG_member, name: "second", scope: !71, file: !72, line: 215, baseType: !93, size: 32, offset: 32)
+!97 = !DISubprogram(name: "pair", scope: !71, file: !72, line: 303, type: !98, isLocal: false, isDefinition: false, scopeLine: 303, flags: DIFlagPrototyped, isOptimized: true)
+!98 = !DISubroutineType(types: !99)
+!99 = !{null, !100, !101}
+!100 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !71, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!101 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !102, size: 64)
+!102 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !71)
+!103 = !DISubprogram(name: "pair", scope: !71, file: !72, line: 304, type: !104, isLocal: false, isDefinition: false, scopeLine: 304, flags: DIFlagPrototyped, isOptimized: true)
+!104 = !DISubroutineType(types: !105)
+!105 = !{null, !100, !106}
+!106 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !71, size: 64)
+!107 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIiiEaSERKS0_", scope: !71, file: !72, line: 378, type: !108, isLocal: false, isDefinition: false, scopeLine: 378, flags: DIFlagPrototyped, isOptimized: true)
+!108 = !DISubroutineType(types: !109)
+!109 = !{!110, !100, !111}
+!110 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !71, size: 64)
+!111 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !113, file: !112, line: 1970, baseType: !101)
+!112 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/type_traits", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!113 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<true, const std::pair<int, int> &, const std::__nonesuch_no_braces &>", scope: !13, file: !112, line: 1969, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !115, identifier: "_ZTSSt11conditionalILb1ERKSt4pairIiiERKSt20__nonesuch_no_bracesE")
+!114 = !{}
+!115 = !{!116, !118, !119}
+!116 = !DITemplateValueParameter(name: "_Cond", type: !117, value: i8 1)
+!117 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean)
+!118 = !DITemplateTypeParameter(name: "_Iftrue", type: !101)
+!119 = !DITemplateTypeParameter(name: "_Iffalse", type: !120)
+!120 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !121, size: 64)
+!121 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !122)
+!122 = !DICompositeType(tag: DW_TAG_structure_type, name: "__nonesuch_no_braces", scope: !13, file: !72, line: 185, flags: DIFlagFwdDecl, identifier: "_ZTSSt20__nonesuch_no_braces")
+!123 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIiiEaSEOS0_", scope: !71, file: !72, line: 389, type: !124, isLocal: false, isDefinition: false, scopeLine: 389, flags: DIFlagPrototyped, isOptimized: true)
+!124 = !DISubroutineType(types: !125)
+!125 = !{!110, !100, !126}
+!126 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !127, file: !112, line: 1970, baseType: !106)
+!127 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<true, std::pair<int, int> &&, std::__nonesuch_no_braces &&>", scope: !13, file: !112, line: 1969, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !128, identifier: "_ZTSSt11conditionalILb1EOSt4pairIiiEOSt20__nonesuch_no_bracesE")
+!128 = !{!116, !129, !130}
+!129 = !DITemplateTypeParameter(name: "_Iftrue", type: !106)
+!130 = !DITemplateTypeParameter(name: "_Iffalse", type: !131)
+!131 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !122, size: 64)
+!132 = !DISubprogram(name: "swap", linkageName: "_ZNSt4pairIiiE4swapERS0_", scope: !71, file: !72, line: 424, type: !133, isLocal: false, isDefinition: false, scopeLine: 424, flags: DIFlagPrototyped, isOptimized: true)
+!133 = !DISubroutineType(types: !134)
+!134 = !{null, !100, !110}
+!135 = !{!136, !137}
+!136 = !DITemplateTypeParameter(name: "_T1", type: !93)
+!137 = !DITemplateTypeParameter(name: "_T2", type: !93)
+!138 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !139, size: 64)
+!139 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !63, file: !64, line: 387, baseType: !140)
+!140 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "allocator<std::pair<int, int> >", scope: !13, file: !141, line: 108, size: 8, flags: DIFlagTypePassByReference, elements: !142, templateParams: !186, identifier: "_ZTSSaISt4pairIiiEE")
+!141 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/allocator.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!142 = !{!143, !188, !192, !197}
+!143 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !140, baseType: !144, flags: DIFlagPublic, extraData: i32 0)
+!144 = !DIDerivedType(tag: DW_TAG_typedef, name: "__allocator_base<std::pair<int, int> >", scope: !13, file: !145, line: 48, baseType: !146)
+!145 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/x86_64-pc-linux-gnu/bits/c++allocator.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!146 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "new_allocator<std::pair<int, int> >", scope: !5, file: !147, line: 58, size: 8, flags: DIFlagTypePassByReference, elements: !148, templateParams: !186, identifier: "_ZTSN9__gnu_cxx13new_allocatorISt4pairIiiEEE")
+!147 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/ext/new_allocator.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!148 = !{!149, !153, !158, !159, !165, !171, !180, !183}
+!149 = !DISubprogram(name: "new_allocator", scope: !146, file: !147, line: 79, type: !150, isLocal: false, isDefinition: false, scopeLine: 79, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!150 = !DISubroutineType(types: !151)
+!151 = !{null, !152}
+!152 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !146, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!153 = !DISubprogram(name: "new_allocator", scope: !146, file: !147, line: 81, type: !154, isLocal: false, isDefinition: false, scopeLine: 81, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!154 = !DISubroutineType(types: !155)
+!155 = !{null, !152, !156}
+!156 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !157, size: 64)
+!157 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !146)
+!158 = !DISubprogram(name: "~new_allocator", scope: !146, file: !147, line: 86, type: !150, isLocal: false, isDefinition: false, scopeLine: 86, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!159 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIiiEE7addressERS2_", scope: !146, file: !147, line: 89, type: !160, isLocal: false, isDefinition: false, scopeLine: 89, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!160 = !DISubroutineType(types: !161)
+!161 = !{!162, !163, !164}
+!162 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !146, file: !147, line: 63, baseType: !70)
+!163 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !157, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!164 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !146, file: !147, line: 65, baseType: !110)
+!165 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIiiEE7addressERKS2_", scope: !146, file: !147, line: 93, type: !166, isLocal: false, isDefinition: false, scopeLine: 93, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!166 = !DISubroutineType(types: !167)
+!167 = !{!168, !163, !170}
+!168 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_pointer", scope: !146, file: !147, line: 64, baseType: !169)
+!169 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !102, size: 64)
+!170 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !146, file: !147, line: 66, baseType: !101)
+!171 = !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE8allocateEmPKv", scope: !146, file: !147, line: 99, type: !172, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!172 = !DISubroutineType(types: !173)
+!173 = !{!162, !152, !174, !178}
+!174 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", file: !147, line: 61, baseType: !175)
+!175 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_t", scope: !13, file: !176, line: 238, baseType: !177)
+!176 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/x86_64-pc-linux-gnu/bits/c++config.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!177 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!178 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !179, size: 64)
+!179 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null)
+!180 = !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE10deallocateEPS2_m", scope: !146, file: !147, line: 116, type: !181, isLocal: false, isDefinition: false, scopeLine: 116, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!181 = !DISubroutineType(types: !182)
+!182 = !{null, !152, !162, !174}
+!183 = !DISubprogram(name: "max_size", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIiiEE8max_sizeEv", scope: !146, file: !147, line: 129, type: !184, isLocal: false, isDefinition: false, scopeLine: 129, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!184 = !DISubroutineType(types: !185)
+!185 = !{!174, !163}
+!186 = !{!187}
+!187 = !DITemplateTypeParameter(name: "_Tp", type: !71)
+!188 = !DISubprogram(name: "allocator", scope: !140, file: !141, line: 131, type: !189, isLocal: false, isDefinition: false, scopeLine: 131, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!189 = !DISubroutineType(types: !190)
+!190 = !{null, !191}
+!191 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !140, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!192 = !DISubprogram(name: "allocator", scope: !140, file: !141, line: 133, type: !193, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!193 = !DISubroutineType(types: !194)
+!194 = !{null, !191, !195}
+!195 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !196, size: 64)
+!196 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !140)
+!197 = !DISubprogram(name: "~allocator", scope: !140, file: !141, line: 139, type: !189, isLocal: false, isDefinition: false, scopeLine: 139, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!198 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", file: !64, line: 407, baseType: !175)
+!199 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_mPKv", scope: !63, file: !64, line: 449, type: !200, isLocal: false, isDefinition: false, scopeLine: 449, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!200 = !DISubroutineType(types: !201)
+!201 = !{!69, !138, !198, !202}
+!202 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_void_pointer", file: !64, line: 401, baseType: !178)
+!203 = !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE10deallocateERS2_PS1_m", scope: !63, file: !64, line: 461, type: !204, isLocal: false, isDefinition: false, scopeLine: 461, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!204 = !DISubroutineType(types: !205)
+!205 = !{null, !138, !69, !198}
+!206 = !DISubprogram(name: "max_size", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE8max_sizeERKS2_", scope: !63, file: !64, line: 495, type: !207, isLocal: false, isDefinition: false, scopeLine: 495, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!207 = !DISubroutineType(types: !208)
+!208 = !{!209, !210}
+!209 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !63, file: !64, line: 407, baseType: !175)
+!210 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !211, size: 64)
+!211 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !139)
+!212 = !DISubprogram(name: "select_on_container_copy_construction", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE37select_on_container_copy_constructionERKS2_", scope: !63, file: !64, line: 504, type: !213, isLocal: false, isDefinition: false, scopeLine: 504, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!213 = !DISubroutineType(types: !214)
+!214 = !{!139, !210}
+!215 = !{!216}
+!216 = !DITemplateTypeParameter(name: "_Alloc", type: !140)
+!217 = !DISubprogram(name: "_S_select_on_copy", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E17_S_select_on_copyERKS3_", scope: !60, file: !59, line: 94, type: !218, isLocal: false, isDefinition: false, scopeLine: 94, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!218 = !DISubroutineType(types: !219)
+!219 = !{!140, !195}
+!220 = !DISubprogram(name: "_S_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E10_S_on_swapERS3_S5_", scope: !60, file: !59, line: 97, type: !221, isLocal: false, isDefinition: false, scopeLine: 97, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!221 = !DISubroutineType(types: !222)
+!222 = !{null, !223, !223}
+!223 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !140, size: 64)
+!224 = !DISubprogram(name: "_S_propagate_on_copy_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E27_S_propagate_on_copy_assignEv", scope: !60, file: !59, line: 100, type: !225, isLocal: false, isDefinition: false, scopeLine: 100, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!225 = !DISubroutineType(types: !226)
+!226 = !{!117}
+!227 = !DISubprogram(name: "_S_propagate_on_move_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E27_S_propagate_on_move_assignEv", scope: !60, file: !59, line: 103, type: !225, isLocal: false, isDefinition: false, scopeLine: 103, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!228 = !DISubprogram(name: "_S_propagate_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E20_S_propagate_on_swapEv", scope: !60, file: !59, line: 106, type: !225, isLocal: false, isDefinition: false, scopeLine: 106, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!229 = !DISubprogram(name: "_S_always_equal", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E15_S_always_equalEv", scope: !60, file: !59, line: 109, type: !225, isLocal: false, isDefinition: false, scopeLine: 109, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!230 = !DISubprogram(name: "_S_nothrow_move", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E15_S_nothrow_moveEv", scope: !60, file: !59, line: 112, type: !225, isLocal: false, isDefinition: false, scopeLine: 112, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!231 = !{!216, !232}
+!232 = !DITemplateTypeParameter(type: !71)
+!233 = !DIDerivedType(tag: DW_TAG_member, name: "_M_finish", scope: !53, file: !49, line: 92, baseType: !57, size: 64, offset: 64)
+!234 = !DIDerivedType(tag: DW_TAG_member, name: "_M_end_of_storage", scope: !53, file: !49, line: 93, baseType: !57, size: 64, offset: 128)
+!235 = !DISubprogram(name: "_Vector_impl", scope: !53, file: !49, line: 95, type: !236, isLocal: false, isDefinition: false, scopeLine: 95, flags: DIFlagPrototyped, isOptimized: true)
+!236 = !DISubroutineType(types: !237)
+!237 = !{null, !238}
+!238 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !53, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!239 = !DISubprogram(name: "_Vector_impl", scope: !53, file: !49, line: 99, type: !240, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPrototyped, isOptimized: true)
+!240 = !DISubroutineType(types: !241)
+!241 = !{null, !238, !242}
+!242 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !243, size: 64)
+!243 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !48)
+!244 = !DISubprogram(name: "_Vector_impl", scope: !53, file: !49, line: 104, type: !245, isLocal: false, isDefinition: false, scopeLine: 104, flags: DIFlagPrototyped, isOptimized: true)
+!245 = !DISubroutineType(types: !246)
+!246 = !{null, !238, !247}
+!247 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !48, size: 64)
+!248 = !DISubprogram(name: "_M_swap_data", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE12_Vector_impl12_M_swap_dataERS4_", scope: !53, file: !49, line: 110, type: !249, isLocal: false, isDefinition: false, scopeLine: 110, flags: DIFlagPrototyped, isOptimized: true)
+!249 = !DISubroutineType(types: !250)
+!250 = !{null, !238, !251}
+!251 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !53, size: 64)
+!252 = !DISubprogram(name: "_M_get_Tp_allocator", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE19_M_get_Tp_allocatorEv", scope: !50, file: !49, line: 237, type: !253, isLocal: false, isDefinition: false, scopeLine: 237, flags: DIFlagPrototyped, isOptimized: true)
+!253 = !DISubroutineType(types: !254)
+!254 = !{!255, !256}
+!255 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !48, size: 64)
+!256 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!257 = !DISubprogram(name: "_M_get_Tp_allocator", linkageName: "_ZNKSt12_Vector_baseISt4pairIiiESaIS1_EE19_M_get_Tp_allocatorEv", scope: !50, file: !49, line: 241, type: !258, isLocal: false, isDefinition: false, scopeLine: 241, flags: DIFlagPrototyped, isOptimized: true)
+!258 = !DISubroutineType(types: !259)
+!259 = !{!242, !260}
+!260 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !261, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!261 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !50)
+!262 = !DISubprogram(name: "get_allocator", linkageName: "_ZNKSt12_Vector_baseISt4pairIiiESaIS1_EE13get_allocatorEv", scope: !50, file: !49, line: 245, type: !263, isLocal: false, isDefinition: false, scopeLine: 245, flags: DIFlagPrototyped, isOptimized: true)
+!263 = !DISubroutineType(types: !264)
+!264 = !{!265, !260}
+!265 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !50, file: !49, line: 234, baseType: !140)
+!266 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 248, type: !267, isLocal: false, isDefinition: false, scopeLine: 248, flags: DIFlagPrototyped, isOptimized: true)
+!267 = !DISubroutineType(types: !268)
+!268 = !{null, !256}
+!269 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 251, type: !270, isLocal: false, isDefinition: false, scopeLine: 251, flags: DIFlagPrototyped, isOptimized: true)
+!270 = !DISubroutineType(types: !271)
+!271 = !{null, !256, !272}
+!272 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !273, size: 64)
+!273 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !265)
+!274 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 254, type: !275, isLocal: false, isDefinition: false, scopeLine: 254, flags: DIFlagPrototyped, isOptimized: true)
+!275 = !DISubroutineType(types: !276)
+!276 = !{null, !256, !175}
+!277 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 258, type: !278, isLocal: false, isDefinition: false, scopeLine: 258, flags: DIFlagPrototyped, isOptimized: true)
+!278 = !DISubroutineType(types: !279)
+!279 = !{null, !256, !175, !272}
+!280 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 263, type: !281, isLocal: false, isDefinition: false, scopeLine: 263, flags: DIFlagPrototyped, isOptimized: true)
+!281 = !DISubroutineType(types: !282)
+!282 = !{null, !256, !247}
+!283 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 266, type: !284, isLocal: false, isDefinition: false, scopeLine: 266, flags: DIFlagPrototyped, isOptimized: true)
+!284 = !DISubroutineType(types: !285)
+!285 = !{null, !256, !286}
+!286 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !50, size: 64)
+!287 = !DISubprogram(name: "_Vector_base", scope: !50, file: !49, line: 270, type: !288, isLocal: false, isDefinition: false, scopeLine: 270, flags: DIFlagPrototyped, isOptimized: true)
+!288 = !DISubroutineType(types: !289)
+!289 = !{null, !256, !286, !272}
+!290 = !DISubprogram(name: "~_Vector_base", scope: !50, file: !49, line: 283, type: !267, isLocal: false, isDefinition: false, scopeLine: 283, flags: DIFlagPrototyped, isOptimized: true)
+!291 = !DISubprogram(name: "_M_allocate", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE11_M_allocateEm", scope: !50, file: !49, line: 293, type: !292, isLocal: false, isDefinition: false, scopeLine: 293, flags: DIFlagPrototyped, isOptimized: true)
+!292 = !DISubroutineType(types: !293)
+!293 = !{!57, !256, !175}
+!294 = !DISubprogram(name: "_M_deallocate", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE13_M_deallocateEPS1_m", scope: !50, file: !49, line: 300, type: !295, isLocal: false, isDefinition: false, scopeLine: 300, flags: DIFlagPrototyped, isOptimized: true)
+!295 = !DISubroutineType(types: !296)
+!296 = !{null, !256, !57, !175}
+!297 = !DISubprogram(name: "_M_create_storage", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE17_M_create_storageEm", scope: !50, file: !49, line: 309, type: !275, isLocal: false, isDefinition: false, scopeLine: 309, flags: DIFlagPrivate | DIFlagPrototyped, isOptimized: true)
+!298 = !{!187, !216}
+!299 = !DIDerivedType(tag: DW_TAG_typedef, name: "other", scope: !300, file: !59, line: 117, baseType: !301)
+!300 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "rebind<std::pair<int, int> >", scope: !60, file: !59, line: 116, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !186, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaISt4pairIiiEES2_E6rebindIS2_EE")
+!301 = !DIDerivedType(tag: DW_TAG_typedef, name: "rebind_alloc<std::pair<int, int> >", scope: !63, file: !64, line: 422, baseType: !140)
+!302 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Link_type", scope: !303, file: !12, line: 465, baseType: !550)
+!303 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "_Rb_tree<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >, std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !12, line: 444, size: 384, flags: DIFlagTypePassByReference, elements: !304, templateParams: !983, identifier: "_ZTSSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE")
+!304 = !{!305, !659, !664, !671, !675, !678, !681, !682, !683, !688, !692, !693, !694, !695, !696, !697, !701, !704, !705, !712, !715, !718, !721, !722, !723, !726, !729, !733, !737, !738, !739, !800, !801, !806, !807, !812, !815, !818, !822, !823, !826, !829, !830, !831, !834, !839, !842, !845, !848, !852, !855, !858, !859, !863, !866, !869, !872, !873, !874, !880, !885, !886, !887, !890, !894, !895, !898, !901, !904, !907, !910, !914, !917, !921, !922, !925, !928, !931, !932, !933, !934, !935, !939, !943, !944, !947, !965, !981, !982}
+!305 = !DIDerivedType(tag: DW_TAG_member, name: "_M_impl", scope: !303, file: !12, line: 724, baseType: !306, size: 384, flags: DIFlagProtected)
+!306 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_impl<std::less<std::__cxx11::basic_string<char> >, true>", scope: !303, file: !12, line: 692, size: 384, flags: DIFlagTypePassByReference, elements: !307, templateParams: !657, identifier: "_ZTSNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE13_Rb_tree_implISC_Lb1EEE")
+!307 = !{!308, !582, !622, !640, !644, !649, !653}
+!308 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !306, baseType: !309, extraData: i32 0)
+!309 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Node_allocator", scope: !303, file: !12, line: 447, baseType: !310)
+!310 = !DIDerivedType(tag: DW_TAG_typedef, name: "other", scope: !311, file: !59, line: 117, baseType: !529)
+!311 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "rebind<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !312, file: !59, line: 116, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !461, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E6rebindISt13_Rb_tree_nodeIS9_EEE")
+!312 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__alloc_traits<std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !5, file: !59, line: 50, size: 8, flags: DIFlagTypePassByValue, elements: !313, templateParams: !459, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_EE")
+!313 = !{!314, !447, !450, !454, !455, !456, !457, !458}
+!314 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !312, baseType: !315, extraData: i32 0)
+!315 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "allocator_traits<std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !64, line: 384, size: 8, flags: DIFlagTypePassByValue, elements: !316, templateParams: !445, identifier: "_ZTSSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE")
+!316 = !{!317, !430, !433, !436, !442}
+!317 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE8allocateERS9_m", scope: !315, file: !64, line: 435, type: !318, isLocal: false, isDefinition: false, scopeLine: 435, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!318 = !DISubroutineType(types: !319)
+!319 = !{!320, !379, !198}
+!320 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !315, file: !64, line: 392, baseType: !321)
+!321 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !322, size: 64)
+!322 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >", scope: !13, file: !72, line: 208, size: 512, flags: DIFlagTypePassByReference, elements: !323, templateParams: !376, identifier: "_ZTSSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_E")
+!323 = !{!324, !345, !346, !347, !353, !357, !366, !373}
+!324 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !322, baseType: !325, flags: DIFlagPrivate, extraData: i32 0)
+!325 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "__pair_base<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >", scope: !13, file: !72, line: 190, size: 8, flags: DIFlagTypePassByValue, elements: !326, templateParams: !341, identifier: "_ZTSSt11__pair_baseIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_E")
+!326 = !{!327, !331, !332, !337}
+!327 = !DISubprogram(name: "__pair_base", scope: !325, file: !72, line: 194, type: !328, isLocal: false, isDefinition: false, scopeLine: 194, flags: DIFlagPrototyped, isOptimized: true)
+!328 = !DISubroutineType(types: !329)
+!329 = !{null, !330}
+!330 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !325, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!331 = !DISubprogram(name: "~__pair_base", scope: !325, file: !72, line: 195, type: !328, isLocal: false, isDefinition: false, scopeLine: 195, flags: DIFlagPrototyped, isOptimized: true)
+!332 = !DISubprogram(name: "__pair_base", scope: !325, file: !72, line: 196, type: !333, isLocal: false, isDefinition: false, scopeLine: 196, flags: DIFlagPrototyped, isOptimized: true)
+!333 = !DISubroutineType(types: !334)
+!334 = !{null, !330, !335}
+!335 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !336, size: 64)
+!336 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !325)
+!337 = !DISubprogram(name: "operator=", linkageName: "_ZNSt11__pair_baseIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EaSERKS7_", scope: !325, file: !72, line: 197, type: !338, isLocal: false, isDefinition: false, scopeLine: 197, flags: DIFlagPrototyped, isOptimized: true)
+!338 = !DISubroutineType(types: !339)
+!339 = !{!340, !330, !335}
+!340 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !325, size: 64)
+!341 = !{!342, !344}
+!342 = !DITemplateTypeParameter(name: "_U1", type: !343)
+!343 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !31)
+!344 = !DITemplateTypeParameter(name: "_U2", type: !31)
+!345 = !DIDerivedType(tag: DW_TAG_member, name: "first", scope: !322, file: !72, line: 214, baseType: !343, size: 256)
+!346 = !DIDerivedType(tag: DW_TAG_member, name: "second", scope: !322, file: !72, line: 215, baseType: !31, size: 256, offset: 256)
+!347 = !DISubprogram(name: "pair", scope: !322, file: !72, line: 303, type: !348, isLocal: false, isDefinition: false, scopeLine: 303, flags: DIFlagPrototyped, isOptimized: true)
+!348 = !DISubroutineType(types: !349)
+!349 = !{null, !350, !351}
+!350 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !322, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!351 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !352, size: 64)
+!352 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !322)
+!353 = !DISubprogram(name: "pair", scope: !322, file: !72, line: 304, type: !354, isLocal: false, isDefinition: false, scopeLine: 304, flags: DIFlagPrototyped, isOptimized: true)
+!354 = !DISubroutineType(types: !355)
+!355 = !{null, !350, !356}
+!356 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !322, size: 64)
+!357 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EaSERKSt20__nonesuch_no_braces", scope: !322, file: !72, line: 378, type: !358, isLocal: false, isDefinition: false, scopeLine: 378, flags: DIFlagPrototyped, isOptimized: true)
+!358 = !DISubroutineType(types: !359)
+!359 = !{!360, !350, !361}
+!360 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !322, size: 64)
+!361 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !362, file: !112, line: 1975, baseType: !120)
+!362 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<false, const std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > &, const std::__nonesuch_no_braces &>", scope: !13, file: !112, line: 1974, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !363, identifier: "_ZTSSt11conditionalILb0ERKSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_ERKSt20__nonesuch_no_bracesE")
+!363 = !{!364, !365, !119}
+!364 = !DITemplateValueParameter(name: "_Cond", type: !117, value: i8 0)
+!365 = !DITemplateTypeParameter(name: "_Iftrue", type: !351)
+!366 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EaSEOSt20__nonesuch_no_braces", scope: !322, file: !72, line: 389, type: !367, isLocal: false, isDefinition: false, scopeLine: 389, flags: DIFlagPrototyped, isOptimized: true)
+!367 = !DISubroutineType(types: !368)
+!368 = !{!360, !350, !369}
+!369 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !370, file: !112, line: 1975, baseType: !131)
+!370 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<false, std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > &&, std::__nonesuch_no_braces &&>", scope: !13, file: !112, line: 1974, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !371, identifier: "_ZTSSt11conditionalILb0EOSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EOSt20__nonesuch_no_bracesE")
+!371 = !{!364, !372, !130}
+!372 = !DITemplateTypeParameter(name: "_Iftrue", type: !356)
+!373 = !DISubprogram(name: "swap", linkageName: "_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_E4swapERS7_", scope: !322, file: !72, line: 424, type: !374, isLocal: false, isDefinition: false, scopeLine: 424, flags: DIFlagPrototyped, isOptimized: true)
+!374 = !DISubroutineType(types: !375)
+!375 = !{null, !350, !360}
+!376 = !{!377, !378}
+!377 = !DITemplateTypeParameter(name: "_T1", type: !343)
+!378 = !DITemplateTypeParameter(name: "_T2", type: !31)
+!379 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !380, size: 64)
+!380 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !315, file: !64, line: 387, baseType: !381)
+!381 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !141, line: 108, size: 8, flags: DIFlagTypePassByReference, elements: !382, templateParams: !418, identifier: "_ZTSSaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EE")
+!382 = !{!383, !420, !424, !429}
+!383 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !381, baseType: !384, flags: DIFlagPublic, extraData: i32 0)
+!384 = !DIDerivedType(tag: DW_TAG_typedef, name: "__allocator_base<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !145, line: 48, baseType: !385)
+!385 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "new_allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !5, file: !147, line: 58, size: 8, flags: DIFlagTypePassByReference, elements: !386, templateParams: !418, identifier: "_ZTSN9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEE")
+!386 = !{!387, !391, !396, !397, !403, !409, !412, !415}
+!387 = !DISubprogram(name: "new_allocator", scope: !385, file: !147, line: 79, type: !388, isLocal: false, isDefinition: false, scopeLine: 79, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!388 = !DISubroutineType(types: !389)
+!389 = !{null, !390}
+!390 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !385, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!391 = !DISubprogram(name: "new_allocator", scope: !385, file: !147, line: 81, type: !392, isLocal: false, isDefinition: false, scopeLine: 81, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!392 = !DISubroutineType(types: !393)
+!393 = !{null, !390, !394}
+!394 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !395, size: 64)
+!395 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !385)
+!396 = !DISubprogram(name: "~new_allocator", scope: !385, file: !147, line: 86, type: !388, isLocal: false, isDefinition: false, scopeLine: 86, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!397 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE7addressERS9_", scope: !385, file: !147, line: 89, type: !398, isLocal: false, isDefinition: false, scopeLine: 89, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!398 = !DISubroutineType(types: !399)
+!399 = !{!400, !401, !402}
+!400 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !385, file: !147, line: 63, baseType: !321)
+!401 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !395, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!402 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !385, file: !147, line: 65, baseType: !360)
+!403 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE7addressERKS9_", scope: !385, file: !147, line: 93, type: !404, isLocal: false, isDefinition: false, scopeLine: 93, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!404 = !DISubroutineType(types: !405)
+!405 = !{!406, !401, !408}
+!406 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_pointer", scope: !385, file: !147, line: 64, baseType: !407)
+!407 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !352, size: 64)
+!408 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !385, file: !147, line: 66, baseType: !351)
+!409 = !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE8allocateEmPKv", scope: !385, file: !147, line: 99, type: !410, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!410 = !DISubroutineType(types: !411)
+!411 = !{!400, !390, !174, !178}
+!412 = !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE10deallocateEPS9_m", scope: !385, file: !147, line: 116, type: !413, isLocal: false, isDefinition: false, scopeLine: 116, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!413 = !DISubroutineType(types: !414)
+!414 = !{null, !390, !400, !174}
+!415 = !DISubprogram(name: "max_size", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE8max_sizeEv", scope: !385, file: !147, line: 129, type: !416, isLocal: false, isDefinition: false, scopeLine: 129, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!416 = !DISubroutineType(types: !417)
+!417 = !{!174, !401}
+!418 = !{!419}
+!419 = !DITemplateTypeParameter(name: "_Tp", type: !322)
+!420 = !DISubprogram(name: "allocator", scope: !381, file: !141, line: 131, type: !421, isLocal: false, isDefinition: false, scopeLine: 131, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!421 = !DISubroutineType(types: !422)
+!422 = !{null, !423}
+!423 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !381, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!424 = !DISubprogram(name: "allocator", scope: !381, file: !141, line: 133, type: !425, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!425 = !DISubroutineType(types: !426)
+!426 = !{null, !423, !427}
+!427 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !428, size: 64)
+!428 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !381)
+!429 = !DISubprogram(name: "~allocator", scope: !381, file: !141, line: 139, type: !421, isLocal: false, isDefinition: false, scopeLine: 139, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!430 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE8allocateERS9_mPKv", scope: !315, file: !64, line: 449, type: !431, isLocal: false, isDefinition: false, scopeLine: 449, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!431 = !DISubroutineType(types: !432)
+!432 = !{!320, !379, !198, !202}
+!433 = !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE10deallocateERS9_PS8_m", scope: !315, file: !64, line: 461, type: !434, isLocal: false, isDefinition: false, scopeLine: 461, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!434 = !DISubroutineType(types: !435)
+!435 = !{null, !379, !320, !198}
+!436 = !DISubprogram(name: "max_size", linkageName: "_ZNSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE8max_sizeERKS9_", scope: !315, file: !64, line: 495, type: !437, isLocal: false, isDefinition: false, scopeLine: 495, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!437 = !DISubroutineType(types: !438)
+!438 = !{!439, !440}
+!439 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !315, file: !64, line: 407, baseType: !175)
+!440 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !441, size: 64)
+!441 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !380)
+!442 = !DISubprogram(name: "select_on_container_copy_construction", linkageName: "_ZNSt16allocator_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE37select_on_container_copy_constructionERKS9_", scope: !315, file: !64, line: 504, type: !443, isLocal: false, isDefinition: false, scopeLine: 504, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!443 = !DISubroutineType(types: !444)
+!444 = !{!380, !440}
+!445 = !{!446}
+!446 = !DITemplateTypeParameter(name: "_Alloc", type: !381)
+!447 = !DISubprogram(name: "_S_select_on_copy", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E17_S_select_on_copyERKSA_", scope: !312, file: !59, line: 94, type: !448, isLocal: false, isDefinition: false, scopeLine: 94, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!448 = !DISubroutineType(types: !449)
+!449 = !{!381, !427}
+!450 = !DISubprogram(name: "_S_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E10_S_on_swapERSA_SC_", scope: !312, file: !59, line: 97, type: !451, isLocal: false, isDefinition: false, scopeLine: 97, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!451 = !DISubroutineType(types: !452)
+!452 = !{null, !453, !453}
+!453 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !381, size: 64)
+!454 = !DISubprogram(name: "_S_propagate_on_copy_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E27_S_propagate_on_copy_assignEv", scope: !312, file: !59, line: 100, type: !225, isLocal: false, isDefinition: false, scopeLine: 100, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!455 = !DISubprogram(name: "_S_propagate_on_move_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E27_S_propagate_on_move_assignEv", scope: !312, file: !59, line: 103, type: !225, isLocal: false, isDefinition: false, scopeLine: 103, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!456 = !DISubprogram(name: "_S_propagate_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E20_S_propagate_on_swapEv", scope: !312, file: !59, line: 106, type: !225, isLocal: false, isDefinition: false, scopeLine: 106, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!457 = !DISubprogram(name: "_S_always_equal", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E15_S_always_equalEv", scope: !312, file: !59, line: 109, type: !225, isLocal: false, isDefinition: false, scopeLine: 109, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!458 = !DISubprogram(name: "_S_nothrow_move", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EES9_E15_S_nothrow_moveEv", scope: !312, file: !59, line: 112, type: !225, isLocal: false, isDefinition: false, scopeLine: 112, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!459 = !{!446, !460}
+!460 = !DITemplateTypeParameter(type: !322)
+!461 = !{!462}
+!462 = !DITemplateTypeParameter(name: "_Tp", type: !463)
+!463 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !12, line: 216, size: 768, flags: DIFlagTypePassByValue, elements: !464, templateParams: !527, identifier: "_ZTSSt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE")
+!464 = !{!465, !485, !518, !522}
+!465 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !463, baseType: !466, extraData: i32 0)
+!466 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_node_base", scope: !13, file: !12, line: 101, size: 256, flags: DIFlagTypePassByValue, elements: !467, identifier: "_ZTSSt18_Rb_tree_node_base")
+!467 = !{!468, !469, !472, !473, !474, !477, !483, !484}
+!468 = !DIDerivedType(tag: DW_TAG_member, name: "_M_color", scope: !466, file: !12, line: 106, baseType: !11, size: 32)
+!469 = !DIDerivedType(tag: DW_TAG_member, name: "_M_parent", scope: !466, file: !12, line: 107, baseType: !470, size: 64, offset: 64)
+!470 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Base_ptr", scope: !466, file: !12, line: 103, baseType: !471)
+!471 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !466, size: 64)
+!472 = !DIDerivedType(tag: DW_TAG_member, name: "_M_left", scope: !466, file: !12, line: 108, baseType: !470, size: 64, offset: 128)
+!473 = !DIDerivedType(tag: DW_TAG_member, name: "_M_right", scope: !466, file: !12, line: 109, baseType: !470, size: 64, offset: 192)
+!474 = !DISubprogram(name: "_S_minimum", linkageName: "_ZNSt18_Rb_tree_node_base10_S_minimumEPS_", scope: !466, file: !12, line: 112, type: !475, isLocal: false, isDefinition: false, scopeLine: 112, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!475 = !DISubroutineType(types: !476)
+!476 = !{!470, !470}
+!477 = !DISubprogram(name: "_S_minimum", linkageName: "_ZNSt18_Rb_tree_node_base10_S_minimumEPKS_", scope: !466, file: !12, line: 119, type: !478, isLocal: false, isDefinition: false, scopeLine: 119, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!478 = !DISubroutineType(types: !479)
+!479 = !{!480, !480}
+!480 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Const_Base_ptr", scope: !466, file: !12, line: 104, baseType: !481)
+!481 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !482, size: 64)
+!482 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !466)
+!483 = !DISubprogram(name: "_S_maximum", linkageName: "_ZNSt18_Rb_tree_node_base10_S_maximumEPS_", scope: !466, file: !12, line: 126, type: !475, isLocal: false, isDefinition: false, scopeLine: 126, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!484 = !DISubprogram(name: "_S_maximum", linkageName: "_ZNSt18_Rb_tree_node_base10_S_maximumEPKS_", scope: !466, file: !12, line: 133, type: !478, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!485 = !DIDerivedType(tag: DW_TAG_member, name: "_M_storage", scope: !463, file: !12, line: 231, baseType: !486, size: 512, offset: 256)
+!486 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__aligned_membuf<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !5, file: !487, line: 47, size: 512, flags: DIFlagTypePassByValue, elements: !488, templateParams: !418, identifier: "_ZTSN9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEE")
+!487 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/ext/aligned_buffer.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!488 = !{!489, !494, !498, !503, !507, !512, !515}
+!489 = !DIDerivedType(tag: DW_TAG_member, name: "_M_storage", scope: !486, file: !487, line: 54, baseType: !490, size: 512, align: 64)
+!490 = !DICompositeType(tag: DW_TAG_array_type, baseType: !491, size: 512, elements: !492)
+!491 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char)
+!492 = !{!493}
+!493 = !DISubrange(count: 64)
+!494 = !DISubprogram(name: "__aligned_membuf", scope: !486, file: !487, line: 56, type: !495, isLocal: false, isDefinition: false, scopeLine: 56, flags: DIFlagPrototyped, isOptimized: true)
+!495 = !DISubroutineType(types: !496)
+!496 = !{null, !497}
+!497 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !486, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!498 = !DISubprogram(name: "__aligned_membuf", scope: !486, file: !487, line: 59, type: !499, isLocal: false, isDefinition: false, scopeLine: 59, flags: DIFlagPrototyped, isOptimized: true)
+!499 = !DISubroutineType(types: !500)
+!500 = !{null, !497, !501}
+!501 = !DIDerivedType(tag: DW_TAG_typedef, name: "nullptr_t", scope: !13, file: !176, line: 242, baseType: !502)
+!502 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "decltype(nullptr)")
+!503 = !DISubprogram(name: "_M_addr", linkageName: "_ZN9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE7_M_addrEv", scope: !486, file: !487, line: 62, type: !504, isLocal: false, isDefinition: false, scopeLine: 62, flags: DIFlagPrototyped, isOptimized: true)
+!504 = !DISubroutineType(types: !505)
+!505 = !{!506, !497}
+!506 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!507 = !DISubprogram(name: "_M_addr", linkageName: "_ZNK9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE7_M_addrEv", scope: !486, file: !487, line: 66, type: !508, isLocal: false, isDefinition: false, scopeLine: 66, flags: DIFlagPrototyped, isOptimized: true)
+!508 = !DISubroutineType(types: !509)
+!509 = !{!178, !510}
+!510 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !511, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!511 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !486)
+!512 = !DISubprogram(name: "_M_ptr", linkageName: "_ZN9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE6_M_ptrEv", scope: !486, file: !487, line: 70, type: !513, isLocal: false, isDefinition: false, scopeLine: 70, flags: DIFlagPrototyped, isOptimized: true)
+!513 = !DISubroutineType(types: !514)
+!514 = !{!321, !497}
+!515 = !DISubprogram(name: "_M_ptr", linkageName: "_ZNK9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE6_M_ptrEv", scope: !486, file: !487, line: 74, type: !516, isLocal: false, isDefinition: false, scopeLine: 74, flags: DIFlagPrototyped, isOptimized: true)
+!516 = !DISubroutineType(types: !517)
+!517 = !{!407, !510}
+!518 = !DISubprogram(name: "_M_valptr", linkageName: "_ZNSt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE9_M_valptrEv", scope: !463, file: !12, line: 234, type: !519, isLocal: false, isDefinition: false, scopeLine: 234, flags: DIFlagPrototyped, isOptimized: true)
+!519 = !DISubroutineType(types: !520)
+!520 = !{!321, !521}
+!521 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !463, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!522 = !DISubprogram(name: "_M_valptr", linkageName: "_ZNKSt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE9_M_valptrEv", scope: !463, file: !12, line: 238, type: !523, isLocal: false, isDefinition: false, scopeLine: 238, flags: DIFlagPrototyped, isOptimized: true)
+!523 = !DISubroutineType(types: !524)
+!524 = !{!407, !525}
+!525 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !526, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!526 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !463)
+!527 = !{!528}
+!528 = !DITemplateTypeParameter(name: "_Val", type: !322)
+!529 = !DIDerivedType(tag: DW_TAG_typedef, name: "rebind_alloc<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !315, file: !64, line: 422, baseType: !530)
+!530 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "allocator<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !141, line: 108, size: 8, flags: DIFlagTypePassByReference, elements: !531, templateParams: !580, identifier: "_ZTSSaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEE")
+!531 = !{!532, !570, !574, !579}
+!532 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !530, baseType: !533, flags: DIFlagPublic, extraData: i32 0)
+!533 = !DIDerivedType(tag: DW_TAG_typedef, name: "__allocator_base<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !145, line: 48, baseType: !534)
+!534 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "new_allocator<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !5, file: !147, line: 58, size: 8, flags: DIFlagTypePassByReference, elements: !535, templateParams: !461, identifier: "_ZTSN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEEE")
+!535 = !{!536, !540, !545, !546, !554, !561, !564, !567}
+!536 = !DISubprogram(name: "new_allocator", scope: !534, file: !147, line: 79, type: !537, isLocal: false, isDefinition: false, scopeLine: 79, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!537 = !DISubroutineType(types: !538)
+!538 = !{null, !539}
+!539 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !534, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!540 = !DISubprogram(name: "new_allocator", scope: !534, file: !147, line: 81, type: !541, isLocal: false, isDefinition: false, scopeLine: 81, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!541 = !DISubroutineType(types: !542)
+!542 = !{null, !539, !543}
+!543 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !544, size: 64)
+!544 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !534)
+!545 = !DISubprogram(name: "~new_allocator", scope: !534, file: !147, line: 86, type: !537, isLocal: false, isDefinition: false, scopeLine: 86, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!546 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE7addressERSB_", scope: !534, file: !147, line: 89, type: !547, isLocal: false, isDefinition: false, scopeLine: 89, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!547 = !DISubroutineType(types: !548)
+!548 = !{!549, !551, !552}
+!549 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !534, file: !147, line: 63, baseType: !550)
+!550 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !463, size: 64)
+!551 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !544, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!552 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !534, file: !147, line: 65, baseType: !553)
+!553 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !463, size: 64)
+!554 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE7addressERKSB_", scope: !534, file: !147, line: 93, type: !555, isLocal: false, isDefinition: false, scopeLine: 93, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!555 = !DISubroutineType(types: !556)
+!556 = !{!557, !551, !559}
+!557 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_pointer", scope: !534, file: !147, line: 64, baseType: !558)
+!558 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !526, size: 64)
+!559 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !534, file: !147, line: 66, baseType: !560)
+!560 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !526, size: 64)
+!561 = !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE8allocateEmPKv", scope: !534, file: !147, line: 99, type: !562, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!562 = !DISubroutineType(types: !563)
+!563 = !{!549, !539, !174, !178}
+!564 = !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE10deallocateEPSB_m", scope: !534, file: !147, line: 116, type: !565, isLocal: false, isDefinition: false, scopeLine: 116, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!565 = !DISubroutineType(types: !566)
+!566 = !{null, !539, !549, !174}
+!567 = !DISubprogram(name: "max_size", linkageName: "_ZNK9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE8max_sizeEv", scope: !534, file: !147, line: 129, type: !568, isLocal: false, isDefinition: false, scopeLine: 129, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!568 = !DISubroutineType(types: !569)
+!569 = !{!174, !551}
+!570 = !DISubprogram(name: "allocator", scope: !530, file: !141, line: 131, type: !571, isLocal: false, isDefinition: false, scopeLine: 131, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!571 = !DISubroutineType(types: !572)
+!572 = !{null, !573}
+!573 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !530, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!574 = !DISubprogram(name: "allocator", scope: !530, file: !141, line: 133, type: !575, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!575 = !DISubroutineType(types: !576)
+!576 = !{null, !573, !577}
+!577 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !578, size: 64)
+!578 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !530)
+!579 = !DISubprogram(name: "~allocator", scope: !530, file: !141, line: 139, type: !571, isLocal: false, isDefinition: false, scopeLine: 139, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!580 = !{!581}
+!581 = !DITemplateTypeParameter(type: !463)
+!582 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !306, baseType: !583, extraData: i32 0)
+!583 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_key_compare<std::less<std::__cxx11::basic_string<char> > >", scope: !13, file: !12, line: 142, size: 8, flags: DIFlagTypePassByReference, elements: !584, templateParams: !620, identifier: "_ZTSSt20_Rb_tree_key_compareISt4lessINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE")
+!584 = !{!585, !603, !607, !611, !616}
+!585 = !DIDerivedType(tag: DW_TAG_member, name: "_M_key_compare", scope: !583, file: !12, line: 144, baseType: !586, size: 8)
+!586 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "less<std::__cxx11::basic_string<char> >", scope: !13, file: !587, line: 381, size: 8, flags: DIFlagTypePassByValue, elements: !588, templateParams: !601, identifier: "_ZTSSt4lessINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE")
+!587 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_function.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!588 = !{!589, !595}
+!589 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !586, baseType: !590, extraData: i32 0)
+!590 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "binary_function<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, bool>", scope: !13, file: !587, line: 118, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !591, identifier: "_ZTSSt15binary_functionINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_bE")
+!591 = !{!592, !593, !594}
+!592 = !DITemplateTypeParameter(name: "_Arg1", type: !31)
+!593 = !DITemplateTypeParameter(name: "_Arg2", type: !31)
+!594 = !DITemplateTypeParameter(name: "_Result", type: !117)
+!595 = !DISubprogram(name: "operator()", linkageName: "_ZNKSt4lessINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEclERKS5_S8_", scope: !586, file: !587, line: 385, type: !596, isLocal: false, isDefinition: false, scopeLine: 385, flags: DIFlagPrototyped, isOptimized: true)
+!596 = !DISubroutineType(types: !597)
+!597 = !{!117, !598, !600, !600}
+!598 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !599, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!599 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !586)
+!600 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !343, size: 64)
+!601 = !{!602}
+!602 = !DITemplateTypeParameter(name: "_Tp", type: !31)
+!603 = !DISubprogram(name: "_Rb_tree_key_compare", scope: !583, file: !12, line: 146, type: !604, isLocal: false, isDefinition: false, scopeLine: 146, flags: DIFlagPrototyped, isOptimized: true)
+!604 = !DISubroutineType(types: !605)
+!605 = !{null, !606}
+!606 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !583, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!607 = !DISubprogram(name: "_Rb_tree_key_compare", scope: !583, file: !12, line: 152, type: !608, isLocal: false, isDefinition: false, scopeLine: 152, flags: DIFlagPrototyped, isOptimized: true)
+!608 = !DISubroutineType(types: !609)
+!609 = !{null, !606, !610}
+!610 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !599, size: 64)
+!611 = !DISubprogram(name: "_Rb_tree_key_compare", scope: !583, file: !12, line: 158, type: !612, isLocal: false, isDefinition: false, scopeLine: 158, flags: DIFlagPrototyped, isOptimized: true)
+!612 = !DISubroutineType(types: !613)
+!613 = !{null, !606, !614}
+!614 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !615, size: 64)
+!615 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !583)
+!616 = !DISubprogram(name: "_Rb_tree_key_compare", scope: !583, file: !12, line: 160, type: !617, isLocal: false, isDefinition: false, scopeLine: 160, flags: DIFlagPrototyped, isOptimized: true)
+!617 = !DISubroutineType(types: !618)
+!618 = !{null, !606, !619}
+!619 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !583, size: 64)
+!620 = !{!621}
+!621 = !DITemplateTypeParameter(name: "_Key_compare", type: !586)
+!622 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !306, baseType: !623, offset: 64, extraData: i32 0)
+!623 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_header", scope: !13, file: !12, line: 168, size: 320, flags: DIFlagTypePassByReference, elements: !624, identifier: "_ZTSSt15_Rb_tree_header")
+!624 = !{!625, !626, !627, !631, !635, !639}
+!625 = !DIDerivedType(tag: DW_TAG_member, name: "_M_header", scope: !623, file: !12, line: 170, baseType: !466, size: 256)
+!626 = !DIDerivedType(tag: DW_TAG_member, name: "_M_node_count", scope: !623, file: !12, line: 171, baseType: !175, size: 64, offset: 256)
+!627 = !DISubprogram(name: "_Rb_tree_header", scope: !623, file: !12, line: 173, type: !628, isLocal: false, isDefinition: false, scopeLine: 173, flags: DIFlagPrototyped, isOptimized: true)
+!628 = !DISubroutineType(types: !629)
+!629 = !{null, !630}
+!630 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !623, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!631 = !DISubprogram(name: "_Rb_tree_header", scope: !623, file: !12, line: 180, type: !632, isLocal: false, isDefinition: false, scopeLine: 180, flags: DIFlagPrototyped, isOptimized: true)
+!632 = !DISubroutineType(types: !633)
+!633 = !{null, !630, !634}
+!634 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !623, size: 64)
+!635 = !DISubprogram(name: "_M_move_data", linkageName: "_ZNSt15_Rb_tree_header12_M_move_dataERS_", scope: !623, file: !12, line: 193, type: !636, isLocal: false, isDefinition: false, scopeLine: 193, flags: DIFlagPrototyped, isOptimized: true)
+!636 = !DISubroutineType(types: !637)
+!637 = !{null, !630, !638}
+!638 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !623, size: 64)
+!639 = !DISubprogram(name: "_M_reset", linkageName: "_ZNSt15_Rb_tree_header8_M_resetEv", scope: !623, file: !12, line: 206, type: !628, isLocal: false, isDefinition: false, scopeLine: 206, flags: DIFlagPrototyped, isOptimized: true)
+!640 = !DISubprogram(name: "_Rb_tree_impl", scope: !306, file: !12, line: 699, type: !641, isLocal: false, isDefinition: false, scopeLine: 699, flags: DIFlagPrototyped, isOptimized: true)
+!641 = !DISubroutineType(types: !642)
+!642 = !{null, !643}
+!643 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !306, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!644 = !DISubprogram(name: "_Rb_tree_impl", scope: !306, file: !12, line: 706, type: !645, isLocal: false, isDefinition: false, scopeLine: 706, flags: DIFlagPrototyped, isOptimized: true)
+!645 = !DISubroutineType(types: !646)
+!646 = !{null, !643, !647}
+!647 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !648, size: 64)
+!648 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !306)
+!649 = !DISubprogram(name: "_Rb_tree_impl", scope: !306, file: !12, line: 716, type: !650, isLocal: false, isDefinition: false, scopeLine: 716, flags: DIFlagPrototyped, isOptimized: true)
+!650 = !DISubroutineType(types: !651)
+!651 = !{null, !643, !652}
+!652 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !306, size: 64)
+!653 = !DISubprogram(name: "_Rb_tree_impl", scope: !306, file: !12, line: 718, type: !654, isLocal: false, isDefinition: false, scopeLine: 718, flags: DIFlagPrototyped, isOptimized: true)
+!654 = !DISubroutineType(types: !655)
+!655 = !{null, !643, !610, !656}
+!656 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !309, size: 64)
+!657 = !{!621, !658}
+!658 = !DITemplateValueParameter(type: !117, value: i8 1)
+!659 = !DISubprogram(name: "_M_get_Node_allocator", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE21_M_get_Node_allocatorEv", scope: !303, file: !12, line: 585, type: !660, isLocal: false, isDefinition: false, scopeLine: 585, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!660 = !DISubroutineType(types: !661)
+!661 = !{!662, !663}
+!662 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !309, size: 64)
+!663 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !303, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!664 = !DISubprogram(name: "_M_get_Node_allocator", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE21_M_get_Node_allocatorEv", scope: !303, file: !12, line: 589, type: !665, isLocal: false, isDefinition: false, scopeLine: 589, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!665 = !DISubroutineType(types: !666)
+!666 = !{!667, !669}
+!667 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !668, size: 64)
+!668 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !309)
+!669 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !670, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!670 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !303)
+!671 = !DISubprogram(name: "get_allocator", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE13get_allocatorEv", scope: !303, file: !12, line: 593, type: !672, isLocal: false, isDefinition: false, scopeLine: 593, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!672 = !DISubroutineType(types: !673)
+!673 = !{!674, !669}
+!674 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !303, file: !12, line: 582, baseType: !381)
+!675 = !DISubprogram(name: "_M_get_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11_M_get_nodeEv", scope: !303, file: !12, line: 598, type: !676, isLocal: false, isDefinition: false, scopeLine: 598, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!676 = !DISubroutineType(types: !677)
+!677 = !{!302, !663}
+!678 = !DISubprogram(name: "_M_put_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11_M_put_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 602, type: !679, isLocal: false, isDefinition: false, scopeLine: 602, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!679 = !DISubroutineType(types: !680)
+!680 = !{null, !663, !302}
+!681 = !DISubprogram(name: "_M_destroy_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE15_M_destroy_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 659, type: !679, isLocal: false, isDefinition: false, scopeLine: 659, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!682 = !DISubprogram(name: "_M_drop_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_drop_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 667, type: !679, isLocal: false, isDefinition: false, scopeLine: 667, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!683 = !DISubprogram(name: "_M_root", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_M_rootEv", scope: !303, file: !12, line: 728, type: !684, isLocal: false, isDefinition: false, scopeLine: 728, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!684 = !DISubroutineType(types: !685)
+!685 = !{!686, !663}
+!686 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !687, size: 64)
+!687 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Base_ptr", file: !12, line: 463, baseType: !471)
+!688 = !DISubprogram(name: "_M_root", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_M_rootEv", scope: !303, file: !12, line: 732, type: !689, isLocal: false, isDefinition: false, scopeLine: 732, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!689 = !DISubroutineType(types: !690)
+!690 = !{!691, !669}
+!691 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Const_Base_ptr", file: !12, line: 464, baseType: !481)
+!692 = !DISubprogram(name: "_M_leftmost", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11_M_leftmostEv", scope: !303, file: !12, line: 736, type: !684, isLocal: false, isDefinition: false, scopeLine: 736, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!693 = !DISubprogram(name: "_M_leftmost", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11_M_leftmostEv", scope: !303, file: !12, line: 740, type: !689, isLocal: false, isDefinition: false, scopeLine: 740, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!694 = !DISubprogram(name: "_M_rightmost", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_rightmostEv", scope: !303, file: !12, line: 744, type: !684, isLocal: false, isDefinition: false, scopeLine: 744, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!695 = !DISubprogram(name: "_M_rightmost", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_rightmostEv", scope: !303, file: !12, line: 748, type: !689, isLocal: false, isDefinition: false, scopeLine: 748, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!696 = !DISubprogram(name: "_M_begin", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_beginEv", scope: !303, file: !12, line: 752, type: !676, isLocal: false, isDefinition: false, scopeLine: 752, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!697 = !DISubprogram(name: "_M_begin", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_beginEv", scope: !303, file: !12, line: 756, type: !698, isLocal: false, isDefinition: false, scopeLine: 756, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!698 = !DISubroutineType(types: !699)
+!699 = !{!700, !669}
+!700 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Const_Link_type", scope: !303, file: !12, line: 466, baseType: !558)
+!701 = !DISubprogram(name: "_M_end", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6_M_endEv", scope: !303, file: !12, line: 763, type: !702, isLocal: false, isDefinition: false, scopeLine: 763, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!702 = !DISubroutineType(types: !703)
+!703 = !{!687, !663}
+!704 = !DISubprogram(name: "_M_end", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6_M_endEv", scope: !303, file: !12, line: 767, type: !689, isLocal: false, isDefinition: false, scopeLine: 767, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!705 = !DISubprogram(name: "_S_value", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_S_valueEPKSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 771, type: !706, isLocal: false, isDefinition: false, scopeLine: 771, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!706 = !DISubroutineType(types: !707)
+!707 = !{!708, !700}
+!708 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !303, file: !12, line: 579, baseType: !709)
+!709 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !710, size: 64)
+!710 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !711)
+!711 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !303, file: !12, line: 575, baseType: !322)
+!712 = !DISubprogram(name: "_S_key", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6_S_keyEPKSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 775, type: !713, isLocal: false, isDefinition: false, scopeLine: 775, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!713 = !DISubroutineType(types: !714)
+!714 = !{!600, !700}
+!715 = !DISubprogram(name: "_S_left", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_S_leftEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 779, type: !716, isLocal: false, isDefinition: false, scopeLine: 779, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!716 = !DISubroutineType(types: !717)
+!717 = !{!302, !687}
+!718 = !DISubprogram(name: "_S_left", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_S_leftEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 783, type: !719, isLocal: false, isDefinition: false, scopeLine: 783, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!719 = !DISubroutineType(types: !720)
+!720 = !{!700, !691}
+!721 = !DISubprogram(name: "_S_right", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_S_rightEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 787, type: !716, isLocal: false, isDefinition: false, scopeLine: 787, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!722 = !DISubprogram(name: "_S_right", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_S_rightEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 791, type: !719, isLocal: false, isDefinition: false, scopeLine: 791, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!723 = !DISubprogram(name: "_S_value", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_S_valueEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 795, type: !724, isLocal: false, isDefinition: false, scopeLine: 795, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!724 = !DISubroutineType(types: !725)
+!725 = !{!708, !691}
+!726 = !DISubprogram(name: "_S_key", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6_S_keyEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 799, type: !727, isLocal: false, isDefinition: false, scopeLine: 799, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!727 = !DISubroutineType(types: !728)
+!728 = !{!600, !691}
+!729 = !DISubprogram(name: "_S_minimum", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE10_S_minimumEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 803, type: !730, isLocal: false, isDefinition: false, scopeLine: 803, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!730 = !DISubroutineType(types: !731)
+!731 = !{!732, !687}
+!732 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Base_ptr", scope: !303, file: !12, line: 463, baseType: !471)
+!733 = !DISubprogram(name: "_S_minimum", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE10_S_minimumEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 807, type: !734, isLocal: false, isDefinition: false, scopeLine: 807, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!734 = !DISubroutineType(types: !735)
+!735 = !{!736, !691}
+!736 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Const_Base_ptr", scope: !303, file: !12, line: 464, baseType: !481)
+!737 = !DISubprogram(name: "_S_maximum", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE10_S_maximumEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 811, type: !730, isLocal: false, isDefinition: false, scopeLine: 811, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!738 = !DISubprogram(name: "_S_maximum", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE10_S_maximumEPKSt18_Rb_tree_node_base", scope: !303, file: !12, line: 815, type: !734, isLocal: false, isDefinition: false, scopeLine: 815, flags: DIFlagProtected | DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!739 = !DISubprogram(name: "_M_get_insert_unique_pos", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE24_M_get_insert_unique_posERS7_", scope: !303, file: !12, line: 833, type: !740, isLocal: false, isDefinition: false, scopeLine: 833, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!740 = !DISubroutineType(types: !741)
+!741 = !{!742, !663, !797}
+!742 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "pair<std::_Rb_tree_node_base *, std::_Rb_tree_node_base *>", scope: !13, file: !72, line: 208, size: 128, flags: DIFlagTypePassByValue, elements: !743, templateParams: !794, identifier: "_ZTSSt4pairIPSt18_Rb_tree_node_baseS1_E")
+!743 = !{!744, !764, !765, !766, !772, !776, !784, !791}
+!744 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !742, baseType: !745, flags: DIFlagPrivate, extraData: i32 0)
+!745 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "__pair_base<std::_Rb_tree_node_base *, std::_Rb_tree_node_base *>", scope: !13, file: !72, line: 190, size: 8, flags: DIFlagTypePassByValue, elements: !746, templateParams: !761, identifier: "_ZTSSt11__pair_baseIPSt18_Rb_tree_node_baseS1_E")
+!746 = !{!747, !751, !752, !757}
+!747 = !DISubprogram(name: "__pair_base", scope: !745, file: !72, line: 194, type: !748, isLocal: false, isDefinition: false, scopeLine: 194, flags: DIFlagPrototyped, isOptimized: true)
+!748 = !DISubroutineType(types: !749)
+!749 = !{null, !750}
+!750 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !745, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!751 = !DISubprogram(name: "~__pair_base", scope: !745, file: !72, line: 195, type: !748, isLocal: false, isDefinition: false, scopeLine: 195, flags: DIFlagPrototyped, isOptimized: true)
+!752 = !DISubprogram(name: "__pair_base", scope: !745, file: !72, line: 196, type: !753, isLocal: false, isDefinition: false, scopeLine: 196, flags: DIFlagPrototyped, isOptimized: true)
+!753 = !DISubroutineType(types: !754)
+!754 = !{null, !750, !755}
+!755 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !756, size: 64)
+!756 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !745)
+!757 = !DISubprogram(name: "operator=", linkageName: "_ZNSt11__pair_baseIPSt18_Rb_tree_node_baseS1_EaSERKS2_", scope: !745, file: !72, line: 197, type: !758, isLocal: false, isDefinition: false, scopeLine: 197, flags: DIFlagPrototyped, isOptimized: true)
+!758 = !DISubroutineType(types: !759)
+!759 = !{!760, !750, !755}
+!760 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !745, size: 64)
+!761 = !{!762, !763}
+!762 = !DITemplateTypeParameter(name: "_U1", type: !471)
+!763 = !DITemplateTypeParameter(name: "_U2", type: !471)
+!764 = !DIDerivedType(tag: DW_TAG_member, name: "first", scope: !742, file: !72, line: 214, baseType: !471, size: 64)
+!765 = !DIDerivedType(tag: DW_TAG_member, name: "second", scope: !742, file: !72, line: 215, baseType: !471, size: 64, offset: 64)
+!766 = !DISubprogram(name: "pair", scope: !742, file: !72, line: 303, type: !767, isLocal: false, isDefinition: false, scopeLine: 303, flags: DIFlagPrototyped, isOptimized: true)
+!767 = !DISubroutineType(types: !768)
+!768 = !{null, !769, !770}
+!769 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !742, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!770 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !771, size: 64)
+!771 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !742)
+!772 = !DISubprogram(name: "pair", scope: !742, file: !72, line: 304, type: !773, isLocal: false, isDefinition: false, scopeLine: 304, flags: DIFlagPrototyped, isOptimized: true)
+!773 = !DISubroutineType(types: !774)
+!774 = !{null, !769, !775}
+!775 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !742, size: 64)
+!776 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIPSt18_Rb_tree_node_baseS1_EaSERKS2_", scope: !742, file: !72, line: 378, type: !777, isLocal: false, isDefinition: false, scopeLine: 378, flags: DIFlagPrototyped, isOptimized: true)
+!777 = !DISubroutineType(types: !778)
+!778 = !{!779, !769, !780}
+!779 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !742, size: 64)
+!780 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !781, file: !112, line: 1970, baseType: !770)
+!781 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<true, const std::pair<std::_Rb_tree_node_base *, std::_Rb_tree_node_base *> &, const std::__nonesuch_no_braces &>", scope: !13, file: !112, line: 1969, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !782, identifier: "_ZTSSt11conditionalILb1ERKSt4pairIPSt18_Rb_tree_node_baseS2_ERKSt20__nonesuch_no_bracesE")
+!782 = !{!116, !783, !119}
+!783 = !DITemplateTypeParameter(name: "_Iftrue", type: !770)
+!784 = !DISubprogram(name: "operator=", linkageName: "_ZNSt4pairIPSt18_Rb_tree_node_baseS1_EaSEOS2_", scope: !742, file: !72, line: 389, type: !785, isLocal: false, isDefinition: false, scopeLine: 389, flags: DIFlagPrototyped, isOptimized: true)
+!785 = !DISubroutineType(types: !786)
+!786 = !{!779, !769, !787}
+!787 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !788, file: !112, line: 1970, baseType: !775)
+!788 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<true, std::pair<std::_Rb_tree_node_base *, std::_Rb_tree_node_base *> &&, std::__nonesuch_no_braces &&>", scope: !13, file: !112, line: 1969, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !789, identifier: "_ZTSSt11conditionalILb1EOSt4pairIPSt18_Rb_tree_node_baseS2_EOSt20__nonesuch_no_bracesE")
+!789 = !{!116, !790, !130}
+!790 = !DITemplateTypeParameter(name: "_Iftrue", type: !775)
+!791 = !DISubprogram(name: "swap", linkageName: "_ZNSt4pairIPSt18_Rb_tree_node_baseS1_E4swapERS2_", scope: !742, file: !72, line: 424, type: !792, isLocal: false, isDefinition: false, scopeLine: 424, flags: DIFlagPrototyped, isOptimized: true)
+!792 = !DISubroutineType(types: !793)
+!793 = !{null, !769, !779}
+!794 = !{!795, !796}
+!795 = !DITemplateTypeParameter(name: "_T1", type: !471)
+!796 = !DITemplateTypeParameter(name: "_T2", type: !471)
+!797 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !798, size: 64)
+!798 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !799)
+!799 = !DIDerivedType(tag: DW_TAG_typedef, name: "key_type", scope: !303, file: !12, line: 574, baseType: !31)
+!800 = !DISubprogram(name: "_M_get_insert_equal_pos", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE23_M_get_insert_equal_posERS7_", scope: !303, file: !12, line: 836, type: !740, isLocal: false, isDefinition: false, scopeLine: 836, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!801 = !DISubprogram(name: "_M_get_insert_hint_unique_pos", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE29_M_get_insert_hint_unique_posESt23_Rb_tree_const_iteratorIS8_ERS7_", scope: !303, file: !12, line: 839, type: !802, isLocal: false, isDefinition: false, scopeLine: 839, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!802 = !DISubroutineType(types: !803)
+!803 = !{!742, !663, !804, !797}
+!804 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_iterator", scope: !303, file: !12, line: 820, baseType: !805)
+!805 = !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !12, line: 326, flags: DIFlagFwdDecl, identifier: "_ZTSSt23_Rb_tree_const_iteratorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE")
+!806 = !DISubprogram(name: "_M_get_insert_hint_equal_pos", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE28_M_get_insert_hint_equal_posESt23_Rb_tree_const_iteratorIS8_ERS7_", scope: !303, file: !12, line: 843, type: !802, isLocal: false, isDefinition: false, scopeLine: 843, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!807 = !DISubprogram(name: "_M_insert_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_insert_nodeEPSt18_Rb_tree_node_baseSG_PSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 853, type: !808, isLocal: false, isDefinition: false, scopeLine: 853, flags: DIFlagPrototyped, isOptimized: true)
+!808 = !DISubroutineType(types: !809)
+!809 = !{!810, !663, !687, !687, !302}
+!810 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator", scope: !303, file: !12, line: 819, baseType: !811)
+!811 = !DICompositeType(tag: DW_TAG_structure_type, name: "_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !12, line: 256, flags: DIFlagFwdDecl, identifier: "_ZTSSt17_Rb_tree_iteratorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE")
+!812 = !DISubprogram(name: "_M_insert_lower_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE20_M_insert_lower_nodeEPSt18_Rb_tree_node_basePSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 864, type: !813, isLocal: false, isDefinition: false, scopeLine: 864, flags: DIFlagPrototyped, isOptimized: true)
+!813 = !DISubroutineType(types: !814)
+!814 = !{!810, !663, !687, !302}
+!815 = !DISubprogram(name: "_M_insert_equal_lower_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE26_M_insert_equal_lower_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 867, type: !816, isLocal: false, isDefinition: false, scopeLine: 867, flags: DIFlagPrototyped, isOptimized: true)
+!816 = !DISubroutineType(types: !817)
+!817 = !{!810, !663, !302}
+!818 = !DISubprogram(name: "_M_copy", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_M_copyERKSE_", scope: !303, file: !12, line: 899, type: !819, isLocal: false, isDefinition: false, scopeLine: 899, flags: DIFlagPrototyped, isOptimized: true)
+!819 = !DISubroutineType(types: !820)
+!820 = !{!302, !663, !821}
+!821 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !670, size: 64)
+!822 = !DISubprogram(name: "_M_erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 906, type: !679, isLocal: false, isDefinition: false, scopeLine: 906, flags: DIFlagPrototyped, isOptimized: true)
+!823 = !DISubprogram(name: "_M_lower_bound", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_lower_boundEPSt13_Rb_tree_nodeIS8_EPSt18_Rb_tree_node_baseRS7_", scope: !303, file: !12, line: 909, type: !824, isLocal: false, isDefinition: false, scopeLine: 909, flags: DIFlagPrototyped, isOptimized: true)
+!824 = !DISubroutineType(types: !825)
+!825 = !{!810, !663, !302, !687, !600}
+!826 = !DISubprogram(name: "_M_lower_bound", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_lower_boundEPKSt13_Rb_tree_nodeIS8_EPKSt18_Rb_tree_node_baseRS7_", scope: !303, file: !12, line: 913, type: !827, isLocal: false, isDefinition: false, scopeLine: 913, flags: DIFlagPrototyped, isOptimized: true)
+!827 = !DISubroutineType(types: !828)
+!828 = !{!804, !669, !700, !691, !600}
+!829 = !DISubprogram(name: "_M_upper_bound", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_upper_boundEPSt13_Rb_tree_nodeIS8_EPSt18_Rb_tree_node_baseRS7_", scope: !303, file: !12, line: 917, type: !824, isLocal: false, isDefinition: false, scopeLine: 917, flags: DIFlagPrototyped, isOptimized: true)
+!830 = !DISubprogram(name: "_M_upper_bound", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_upper_boundEPKSt13_Rb_tree_nodeIS8_EPKSt18_Rb_tree_node_baseRS7_", scope: !303, file: !12, line: 921, type: !827, isLocal: false, isDefinition: false, scopeLine: 921, flags: DIFlagPrototyped, isOptimized: true)
+!831 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 929, type: !832, isLocal: false, isDefinition: false, scopeLine: 929, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!832 = !DISubroutineType(types: !833)
+!833 = !{null, !663}
+!834 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 932, type: !835, isLocal: false, isDefinition: false, scopeLine: 932, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!835 = !DISubroutineType(types: !836)
+!836 = !{null, !663, !610, !837}
+!837 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !838, size: 64)
+!838 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !674)
+!839 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 936, type: !840, isLocal: false, isDefinition: false, scopeLine: 936, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!840 = !DISubroutineType(types: !841)
+!841 = !{null, !663, !821}
+!842 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 944, type: !843, isLocal: false, isDefinition: false, scopeLine: 944, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!843 = !DISubroutineType(types: !844)
+!844 = !{null, !663, !837}
+!845 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 948, type: !846, isLocal: false, isDefinition: false, scopeLine: 948, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!846 = !DISubroutineType(types: !847)
+!847 = !{null, !663, !821, !837}
+!848 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 955, type: !849, isLocal: false, isDefinition: false, scopeLine: 955, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!849 = !DISubroutineType(types: !850)
+!850 = !{null, !663, !851}
+!851 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !303, size: 64)
+!852 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 957, type: !853, isLocal: false, isDefinition: false, scopeLine: 957, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!853 = !DISubroutineType(types: !854)
+!854 = !{null, !663, !851, !837}
+!855 = !DISubprogram(name: "_Rb_tree", scope: !303, file: !12, line: 961, type: !856, isLocal: false, isDefinition: false, scopeLine: 961, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!856 = !DISubroutineType(types: !857)
+!857 = !{null, !663, !851, !656}
+!858 = !DISubprogram(name: "~_Rb_tree", scope: !303, file: !12, line: 964, type: !832, isLocal: false, isDefinition: false, scopeLine: 964, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!859 = !DISubprogram(name: "operator=", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EEaSERKSE_", scope: !303, file: !12, line: 968, type: !860, isLocal: false, isDefinition: false, scopeLine: 968, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!860 = !DISubroutineType(types: !861)
+!861 = !{!862, !663, !821}
+!862 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !303, size: 64)
+!863 = !DISubprogram(name: "key_comp", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8key_compEv", scope: !303, file: !12, line: 972, type: !864, isLocal: false, isDefinition: false, scopeLine: 972, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!864 = !DISubroutineType(types: !865)
+!865 = !{!586, !669}
+!866 = !DISubprogram(name: "begin", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5beginEv", scope: !303, file: !12, line: 976, type: !867, isLocal: false, isDefinition: false, scopeLine: 976, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!867 = !DISubroutineType(types: !868)
+!868 = !{!810, !663}
+!869 = !DISubprogram(name: "begin", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5beginEv", scope: !303, file: !12, line: 980, type: !870, isLocal: false, isDefinition: false, scopeLine: 980, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!870 = !DISubroutineType(types: !871)
+!871 = !{!804, !669}
+!872 = !DISubprogram(name: "end", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE3endEv", scope: !303, file: !12, line: 984, type: !867, isLocal: false, isDefinition: false, scopeLine: 984, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!873 = !DISubprogram(name: "end", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE3endEv", scope: !303, file: !12, line: 988, type: !870, isLocal: false, isDefinition: false, scopeLine: 988, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!874 = !DISubprogram(name: "rbegin", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6rbeginEv", scope: !303, file: !12, line: 992, type: !875, isLocal: false, isDefinition: false, scopeLine: 992, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!875 = !DISubroutineType(types: !876)
+!876 = !{!877, !663}
+!877 = !DIDerivedType(tag: DW_TAG_typedef, name: "reverse_iterator", scope: !303, file: !12, line: 822, baseType: !878)
+!878 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorISt17_Rb_tree_iteratorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEE")
+!879 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_iterator.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!880 = !DISubprogram(name: "rbegin", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE6rbeginEv", scope: !303, file: !12, line: 996, type: !881, isLocal: false, isDefinition: false, scopeLine: 996, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!881 = !DISubroutineType(types: !882)
+!882 = !{!883, !669}
+!883 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reverse_iterator", scope: !303, file: !12, line: 823, baseType: !884)
+!884 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<std::_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorISt23_Rb_tree_const_iteratorISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEE")
+!885 = !DISubprogram(name: "rend", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4rendEv", scope: !303, file: !12, line: 1000, type: !875, isLocal: false, isDefinition: false, scopeLine: 1000, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!886 = !DISubprogram(name: "rend", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4rendEv", scope: !303, file: !12, line: 1004, type: !881, isLocal: false, isDefinition: false, scopeLine: 1004, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!887 = !DISubprogram(name: "empty", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5emptyEv", scope: !303, file: !12, line: 1008, type: !888, isLocal: false, isDefinition: false, scopeLine: 1008, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!888 = !DISubroutineType(types: !889)
+!889 = !{!117, !669}
+!890 = !DISubprogram(name: "size", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4sizeEv", scope: !303, file: !12, line: 1012, type: !891, isLocal: false, isDefinition: false, scopeLine: 1012, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!891 = !DISubroutineType(types: !892)
+!892 = !{!893, !669}
+!893 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", file: !12, line: 580, baseType: !175)
+!894 = !DISubprogram(name: "max_size", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8max_sizeEv", scope: !303, file: !12, line: 1016, type: !891, isLocal: false, isDefinition: false, scopeLine: 1016, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!895 = !DISubprogram(name: "swap", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4swapERSE_", scope: !303, file: !12, line: 1020, type: !896, isLocal: false, isDefinition: false, scopeLine: 1020, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!896 = !DISubroutineType(types: !897)
+!897 = !{null, !663, !862}
+!898 = !DISubprogram(name: "_M_erase_aux", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_erase_auxESt23_Rb_tree_const_iteratorIS8_E", scope: !303, file: !12, line: 1113, type: !899, isLocal: false, isDefinition: false, scopeLine: 1113, flags: DIFlagPrototyped, isOptimized: true)
+!899 = !DISubroutineType(types: !900)
+!900 = !{null, !663, !804}
+!901 = !DISubprogram(name: "_M_erase_aux", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_erase_auxESt23_Rb_tree_const_iteratorIS8_ESG_", scope: !303, file: !12, line: 1116, type: !902, isLocal: false, isDefinition: false, scopeLine: 1116, flags: DIFlagPrototyped, isOptimized: true)
+!902 = !DISubroutineType(types: !903)
+!903 = !{null, !663, !804, !804}
+!904 = !DISubprogram(name: "erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5eraseB5cxx11ESt23_Rb_tree_const_iteratorIS8_E", scope: !303, file: !12, line: 1124, type: !905, isLocal: false, isDefinition: false, scopeLine: 1124, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!905 = !DISubroutineType(types: !906)
+!906 = !{!810, !663, !804}
+!907 = !DISubprogram(name: "erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5eraseB5cxx11ESt17_Rb_tree_iteratorIS8_E", scope: !303, file: !12, line: 1136, type: !908, isLocal: false, isDefinition: false, scopeLine: 1136, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!908 = !DISubroutineType(types: !909)
+!909 = !{!810, !663, !810}
+!910 = !DISubprogram(name: "erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5eraseERS7_", scope: !303, file: !12, line: 1160, type: !911, isLocal: false, isDefinition: false, scopeLine: 1160, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!911 = !DISubroutineType(types: !912)
+!912 = !{!913, !663, !797}
+!913 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !303, file: !12, line: 580, baseType: !175)
+!914 = !DISubprogram(name: "erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5eraseB5cxx11ESt23_Rb_tree_const_iteratorIS8_ESG_", scope: !303, file: !12, line: 1167, type: !915, isLocal: false, isDefinition: false, scopeLine: 1167, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!915 = !DISubroutineType(types: !916)
+!916 = !{!810, !663, !804, !804}
+!917 = !DISubprogram(name: "erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5eraseEPS7_SF_", scope: !303, file: !12, line: 1182, type: !918, isLocal: false, isDefinition: false, scopeLine: 1182, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!918 = !DISubroutineType(types: !919)
+!919 = !{null, !663, !920, !920}
+!920 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !798, size: 64)
+!921 = !DISubprogram(name: "clear", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5clearEv", scope: !303, file: !12, line: 1185, type: !832, isLocal: false, isDefinition: false, scopeLine: 1185, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!922 = !DISubprogram(name: "find", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4findERS7_", scope: !303, file: !12, line: 1193, type: !923, isLocal: false, isDefinition: false, scopeLine: 1193, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!923 = !DISubroutineType(types: !924)
+!924 = !{!810, !663, !797}
+!925 = !DISubprogram(name: "find", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE4findERS7_", scope: !303, file: !12, line: 1196, type: !926, isLocal: false, isDefinition: false, scopeLine: 1196, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!926 = !DISubroutineType(types: !927)
+!927 = !{!804, !669, !797}
+!928 = !DISubprogram(name: "count", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE5countERS7_", scope: !303, file: !12, line: 1199, type: !929, isLocal: false, isDefinition: false, scopeLine: 1199, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!929 = !DISubroutineType(types: !930)
+!930 = !{!913, !669, !797}
+!931 = !DISubprogram(name: "lower_bound", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11lower_boundERS7_", scope: !303, file: !12, line: 1202, type: !923, isLocal: false, isDefinition: false, scopeLine: 1202, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!932 = !DISubprogram(name: "lower_bound", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11lower_boundERS7_", scope: !303, file: !12, line: 1206, type: !926, isLocal: false, isDefinition: false, scopeLine: 1206, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!933 = !DISubprogram(name: "upper_bound", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11upper_boundERS7_", scope: !303, file: !12, line: 1210, type: !923, isLocal: false, isDefinition: false, scopeLine: 1210, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!934 = !DISubprogram(name: "upper_bound", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11upper_boundERS7_", scope: !303, file: !12, line: 1214, type: !926, isLocal: false, isDefinition: false, scopeLine: 1214, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!935 = !DISubprogram(name: "equal_range", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11equal_rangeERS7_", scope: !303, file: !12, line: 1218, type: !936, isLocal: false, isDefinition: false, scopeLine: 1218, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!936 = !DISubroutineType(types: !937)
+!937 = !{!938, !663, !797}
+!938 = !DICompositeType(tag: DW_TAG_structure_type, name: "pair<std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !72, line: 208, flags: DIFlagFwdDecl, identifier: "_ZTSSt4pairISt17_Rb_tree_iteratorIS_IKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EES9_E")
+!939 = !DISubprogram(name: "equal_range", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11equal_rangeERS7_", scope: !303, file: !12, line: 1221, type: !940, isLocal: false, isDefinition: false, scopeLine: 1221, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!940 = !DISubroutineType(types: !941)
+!941 = !{!942, !669, !797}
+!942 = !DICompositeType(tag: DW_TAG_structure_type, name: "pair<std::_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, std::_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !72, line: 208, flags: DIFlagFwdDecl, identifier: "_ZTSSt4pairISt23_Rb_tree_const_iteratorIS_IKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EES9_E")
+!943 = !DISubprogram(name: "__rb_verify", linkageName: "_ZNKSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11__rb_verifyEv", scope: !303, file: !12, line: 1342, type: !888, isLocal: false, isDefinition: false, scopeLine: 1342, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!944 = !DISubprogram(name: "operator=", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EEaSEOSE_", scope: !303, file: !12, line: 1346, type: !945, isLocal: false, isDefinition: false, scopeLine: 1346, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!945 = !DISubroutineType(types: !946)
+!946 = !{!862, !663, !851}
+!947 = !DISubprogram(name: "_M_move_data", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_move_dataERSE_St17integral_constantIbLb1EE", scope: !303, file: !12, line: 1361, type: !948, isLocal: false, isDefinition: false, scopeLine: 1361, flags: DIFlagPrototyped, isOptimized: true)
+!948 = !DISubroutineType(types: !949)
+!949 = !{null, !663, !862, !950}
+!950 = !DIDerivedType(tag: DW_TAG_typedef, name: "true_type", scope: !13, file: !112, line: 75, baseType: !951)
+!951 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "integral_constant<bool, true>", scope: !13, file: !112, line: 57, size: 8, flags: DIFlagTypePassByValue, elements: !952, templateParams: !962, identifier: "_ZTSSt17integral_constantIbLb1EE")
+!952 = !{!953, !955, !961}
+!953 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !951, file: !112, line: 59, baseType: !954, flags: DIFlagStaticMember, extraData: i1 true)
+!954 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !117)
+!955 = !DISubprogram(name: "operator bool", linkageName: "_ZNKSt17integral_constantIbLb1EEcvbEv", scope: !951, file: !112, line: 62, type: !956, isLocal: false, isDefinition: false, scopeLine: 62, flags: DIFlagPrototyped, isOptimized: true)
+!956 = !DISubroutineType(types: !957)
+!957 = !{!958, !959}
+!958 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !951, file: !112, line: 60, baseType: !117)
+!959 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !960, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!960 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !951)
+!961 = !DISubprogram(name: "operator()", linkageName: "_ZNKSt17integral_constantIbLb1EEclEv", scope: !951, file: !112, line: 67, type: !956, isLocal: false, isDefinition: false, scopeLine: 67, flags: DIFlagPrototyped, isOptimized: true)
+!962 = !{!963, !964}
+!963 = !DITemplateTypeParameter(name: "_Tp", type: !117)
+!964 = !DITemplateValueParameter(name: "__v", type: !117, value: i8 1)
+!965 = !DISubprogram(name: "_M_move_data", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_move_dataERSE_St17integral_constantIbLb0EE", scope: !303, file: !12, line: 1367, type: !966, isLocal: false, isDefinition: false, scopeLine: 1367, flags: DIFlagPrototyped, isOptimized: true)
+!966 = !DISubroutineType(types: !967)
+!967 = !{null, !663, !862, !968}
+!968 = !DIDerivedType(tag: DW_TAG_typedef, name: "false_type", scope: !13, file: !112, line: 78, baseType: !969)
+!969 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "integral_constant<bool, false>", scope: !13, file: !112, line: 57, size: 8, flags: DIFlagTypePassByValue, elements: !970, templateParams: !979, identifier: "_ZTSSt17integral_constantIbLb0EE")
+!970 = !{!971, !972, !978}
+!971 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !969, file: !112, line: 59, baseType: !954, flags: DIFlagStaticMember, extraData: i1 false)
+!972 = !DISubprogram(name: "operator bool", linkageName: "_ZNKSt17integral_constantIbLb0EEcvbEv", scope: !969, file: !112, line: 62, type: !973, isLocal: false, isDefinition: false, scopeLine: 62, flags: DIFlagPrototyped, isOptimized: true)
+!973 = !DISubroutineType(types: !974)
+!974 = !{!975, !976}
+!975 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !969, file: !112, line: 60, baseType: !117)
+!976 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !977, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!977 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !969)
+!978 = !DISubprogram(name: "operator()", linkageName: "_ZNKSt17integral_constantIbLb0EEclEv", scope: !969, file: !112, line: 67, type: !973, isLocal: false, isDefinition: false, scopeLine: 67, flags: DIFlagPrototyped, isOptimized: true)
+!979 = !{!963, !980}
+!980 = !DITemplateValueParameter(name: "__v", type: !117, value: i8 0)
+!981 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_move_assignERSE_St17integral_constantIbLb1EE", scope: !303, file: !12, line: 1371, type: !948, isLocal: false, isDefinition: false, scopeLine: 1371, flags: DIFlagPrototyped, isOptimized: true)
+!982 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE14_M_move_assignERSE_St17integral_constantIbLb0EE", scope: !303, file: !12, line: 1376, type: !966, isLocal: false, isDefinition: false, scopeLine: 1376, flags: DIFlagPrototyped, isOptimized: true)
+!983 = !{!984, !528, !985, !987, !446}
+!984 = !DITemplateTypeParameter(name: "_Key", type: !31)
+!985 = !DITemplateTypeParameter(name: "_KeyOfValue", type: !986)
+!986 = !DICompositeType(tag: DW_TAG_structure_type, name: "_Select1st<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !587, line: 1123, flags: DIFlagFwdDecl, identifier: "_ZTSSt10_Select1stISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE")
+!987 = !DITemplateTypeParameter(name: "_Compare", type: !586)
+!988 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !989, size: 64)
+!989 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Tp_alloc_type", scope: !990, file: !49, line: 84, baseType: !1156)
+!990 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Vector_base<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >", scope: !13, file: !49, line: 81, size: 192, flags: DIFlagTypePassByReference, elements: !991, templateParams: !1155, identifier: "_ZTSSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE")
+!991 = !{!992, !1109, !1114, !1119, !1123, !1126, !1131, !1134, !1137, !1140, !1144, !1147, !1148, !1151, !1154}
+!992 = !DIDerivedType(tag: DW_TAG_member, name: "_M_impl", scope: !990, file: !49, line: 290, baseType: !993, size: 192)
+!993 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Vector_impl", scope: !990, file: !49, line: 88, size: 192, flags: DIFlagTypePassByReference, elements: !994, identifier: "_ZTSNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12_Vector_implE")
+!994 = !{!995, !996, !1090, !1091, !1092, !1096, !1101, !1105}
+!995 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !993, baseType: !989, extraData: i32 0)
+!996 = !DIDerivedType(tag: DW_TAG_member, name: "_M_start", scope: !993, file: !49, line: 91, baseType: !997, size: 64)
+!997 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !990, file: !49, line: 86, baseType: !998)
+!998 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !999, file: !59, line: 59, baseType: !1007)
+!999 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__alloc_traits<std::allocator<std::__cxx11::basic_string<char> >, std::__cxx11::basic_string<char> >", scope: !5, file: !59, line: 50, size: 8, flags: DIFlagTypePassByValue, elements: !1000, templateParams: !1088, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_EE")
+!1000 = !{!1001, !1076, !1079, !1083, !1084, !1085, !1086, !1087}
+!1001 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !999, baseType: !1002, extraData: i32 0)
+!1002 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "allocator_traits<std::allocator<std::__cxx11::basic_string<char> > >", scope: !13, file: !64, line: 384, size: 8, flags: DIFlagTypePassByValue, elements: !1003, templateParams: !1074, identifier: "_ZTSSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE")
+!1003 = !{!1004, !1059, !1062, !1065, !1071}
+!1004 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_m", scope: !1002, file: !64, line: 435, type: !1005, isLocal: false, isDefinition: false, scopeLine: 435, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1005 = !DISubroutineType(types: !1006)
+!1006 = !{!1007, !1009, !198}
+!1007 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1002, file: !64, line: 392, baseType: !1008)
+!1008 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64)
+!1009 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1010, size: 64)
+!1010 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !1002, file: !64, line: 387, baseType: !1011)
+!1011 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "allocator<std::__cxx11::basic_string<char> >", scope: !13, file: !141, line: 108, size: 8, flags: DIFlagTypePassByReference, elements: !1012, templateParams: !601, identifier: "_ZTSSaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE")
+!1012 = !{!1013, !1049, !1053, !1058}
+!1013 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !1011, baseType: !1014, flags: DIFlagPublic, extraData: i32 0)
+!1014 = !DIDerivedType(tag: DW_TAG_typedef, name: "__allocator_base<std::__cxx11::basic_string<char> >", scope: !13, file: !145, line: 48, baseType: !1015)
+!1015 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "new_allocator<std::__cxx11::basic_string<char> >", scope: !5, file: !147, line: 58, size: 8, flags: DIFlagTypePassByReference, elements: !1016, templateParams: !601, identifier: "_ZTSN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE")
+!1016 = !{!1017, !1021, !1026, !1027, !1034, !1040, !1043, !1046}
+!1017 = !DISubprogram(name: "new_allocator", scope: !1015, file: !147, line: 79, type: !1018, isLocal: false, isDefinition: false, scopeLine: 79, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1018 = !DISubroutineType(types: !1019)
+!1019 = !{null, !1020}
+!1020 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1015, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1021 = !DISubprogram(name: "new_allocator", scope: !1015, file: !147, line: 81, type: !1022, isLocal: false, isDefinition: false, scopeLine: 81, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1022 = !DISubroutineType(types: !1023)
+!1023 = !{null, !1020, !1024}
+!1024 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1025, size: 64)
+!1025 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1015)
+!1026 = !DISubprogram(name: "~new_allocator", scope: !1015, file: !147, line: 86, type: !1018, isLocal: false, isDefinition: false, scopeLine: 86, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1027 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE7addressERS6_", scope: !1015, file: !147, line: 89, type: !1028, isLocal: false, isDefinition: false, scopeLine: 89, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1028 = !DISubroutineType(types: !1029)
+!1029 = !{!1030, !1031, !1032}
+!1030 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1015, file: !147, line: 63, baseType: !1008)
+!1031 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1025, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1032 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !1015, file: !147, line: 65, baseType: !1033)
+!1033 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !31, size: 64)
+!1034 = !DISubprogram(name: "address", linkageName: "_ZNK9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE7addressERKS6_", scope: !1015, file: !147, line: 93, type: !1035, isLocal: false, isDefinition: false, scopeLine: 93, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1035 = !DISubroutineType(types: !1036)
+!1036 = !{!1037, !1031, !1039}
+!1037 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_pointer", scope: !1015, file: !147, line: 64, baseType: !1038)
+!1038 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !343, size: 64)
+!1039 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !1015, file: !147, line: 66, baseType: !600)
+!1040 = !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8allocateEmPKv", scope: !1015, file: !147, line: 99, type: !1041, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1041 = !DISubroutineType(types: !1042)
+!1042 = !{!1030, !1020, !174, !178}
+!1043 = !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE10deallocateEPS6_m", scope: !1015, file: !147, line: 116, type: !1044, isLocal: false, isDefinition: false, scopeLine: 116, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1044 = !DISubroutineType(types: !1045)
+!1045 = !{null, !1020, !1030, !174}
+!1046 = !DISubprogram(name: "max_size", linkageName: "_ZNK9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8max_sizeEv", scope: !1015, file: !147, line: 129, type: !1047, isLocal: false, isDefinition: false, scopeLine: 129, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1047 = !DISubroutineType(types: !1048)
+!1048 = !{!174, !1031}
+!1049 = !DISubprogram(name: "allocator", scope: !1011, file: !141, line: 131, type: !1050, isLocal: false, isDefinition: false, scopeLine: 131, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1050 = !DISubroutineType(types: !1051)
+!1051 = !{null, !1052}
+!1052 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1011, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1053 = !DISubprogram(name: "allocator", scope: !1011, file: !141, line: 133, type: !1054, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1054 = !DISubroutineType(types: !1055)
+!1055 = !{null, !1052, !1056}
+!1056 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1057, size: 64)
+!1057 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1011)
+!1058 = !DISubprogram(name: "~allocator", scope: !1011, file: !141, line: 139, type: !1050, isLocal: false, isDefinition: false, scopeLine: 139, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1059 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_mPKv", scope: !1002, file: !64, line: 449, type: !1060, isLocal: false, isDefinition: false, scopeLine: 449, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1060 = !DISubroutineType(types: !1061)
+!1061 = !{!1007, !1009, !198, !202}
+!1062 = !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE10deallocateERS6_PS5_m", scope: !1002, file: !64, line: 461, type: !1063, isLocal: false, isDefinition: false, scopeLine: 461, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1063 = !DISubroutineType(types: !1064)
+!1064 = !{null, !1009, !1007, !198}
+!1065 = !DISubprogram(name: "max_size", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8max_sizeERKS6_", scope: !1002, file: !64, line: 495, type: !1066, isLocal: false, isDefinition: false, scopeLine: 495, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1066 = !DISubroutineType(types: !1067)
+!1067 = !{!1068, !1069}
+!1068 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !1002, file: !64, line: 407, baseType: !175)
+!1069 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1070, size: 64)
+!1070 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1010)
+!1071 = !DISubprogram(name: "select_on_container_copy_construction", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE37select_on_container_copy_constructionERKS6_", scope: !1002, file: !64, line: 504, type: !1072, isLocal: false, isDefinition: false, scopeLine: 504, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1072 = !DISubroutineType(types: !1073)
+!1073 = !{!1010, !1069}
+!1074 = !{!1075}
+!1075 = !DITemplateTypeParameter(name: "_Alloc", type: !1011)
+!1076 = !DISubprogram(name: "_S_select_on_copy", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E17_S_select_on_copyERKS7_", scope: !999, file: !59, line: 94, type: !1077, isLocal: false, isDefinition: false, scopeLine: 94, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1077 = !DISubroutineType(types: !1078)
+!1078 = !{!1011, !1056}
+!1079 = !DISubprogram(name: "_S_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E10_S_on_swapERS7_S9_", scope: !999, file: !59, line: 97, type: !1080, isLocal: false, isDefinition: false, scopeLine: 97, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1080 = !DISubroutineType(types: !1081)
+!1081 = !{null, !1082, !1082}
+!1082 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1011, size: 64)
+!1083 = !DISubprogram(name: "_S_propagate_on_copy_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E27_S_propagate_on_copy_assignEv", scope: !999, file: !59, line: 100, type: !225, isLocal: false, isDefinition: false, scopeLine: 100, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1084 = !DISubprogram(name: "_S_propagate_on_move_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E27_S_propagate_on_move_assignEv", scope: !999, file: !59, line: 103, type: !225, isLocal: false, isDefinition: false, scopeLine: 103, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1085 = !DISubprogram(name: "_S_propagate_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E20_S_propagate_on_swapEv", scope: !999, file: !59, line: 106, type: !225, isLocal: false, isDefinition: false, scopeLine: 106, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1086 = !DISubprogram(name: "_S_always_equal", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E15_S_always_equalEv", scope: !999, file: !59, line: 109, type: !225, isLocal: false, isDefinition: false, scopeLine: 109, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1087 = !DISubprogram(name: "_S_nothrow_move", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E15_S_nothrow_moveEv", scope: !999, file: !59, line: 112, type: !225, isLocal: false, isDefinition: false, scopeLine: 112, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1088 = !{!1075, !1089}
+!1089 = !DITemplateTypeParameter(type: !31)
+!1090 = !DIDerivedType(tag: DW_TAG_member, name: "_M_finish", scope: !993, file: !49, line: 92, baseType: !997, size: 64, offset: 64)
+!1091 = !DIDerivedType(tag: DW_TAG_member, name: "_M_end_of_storage", scope: !993, file: !49, line: 93, baseType: !997, size: 64, offset: 128)
+!1092 = !DISubprogram(name: "_Vector_impl", scope: !993, file: !49, line: 95, type: !1093, isLocal: false, isDefinition: false, scopeLine: 95, flags: DIFlagPrototyped, isOptimized: true)
+!1093 = !DISubroutineType(types: !1094)
+!1094 = !{null, !1095}
+!1095 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !993, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1096 = !DISubprogram(name: "_Vector_impl", scope: !993, file: !49, line: 99, type: !1097, isLocal: false, isDefinition: false, scopeLine: 99, flags: DIFlagPrototyped, isOptimized: true)
+!1097 = !DISubroutineType(types: !1098)
+!1098 = !{null, !1095, !1099}
+!1099 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1100, size: 64)
+!1100 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !989)
+!1101 = !DISubprogram(name: "_Vector_impl", scope: !993, file: !49, line: 104, type: !1102, isLocal: false, isDefinition: false, scopeLine: 104, flags: DIFlagPrototyped, isOptimized: true)
+!1102 = !DISubroutineType(types: !1103)
+!1103 = !{null, !1095, !1104}
+!1104 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !989, size: 64)
+!1105 = !DISubprogram(name: "_M_swap_data", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12_Vector_impl12_M_swap_dataERS8_", scope: !993, file: !49, line: 110, type: !1106, isLocal: false, isDefinition: false, scopeLine: 110, flags: DIFlagPrototyped, isOptimized: true)
+!1106 = !DISubroutineType(types: !1107)
+!1107 = !{null, !1095, !1108}
+!1108 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !993, size: 64)
+!1109 = !DISubprogram(name: "_M_get_Tp_allocator", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_get_Tp_allocatorEv", scope: !990, file: !49, line: 237, type: !1110, isLocal: false, isDefinition: false, scopeLine: 237, flags: DIFlagPrototyped, isOptimized: true)
+!1110 = !DISubroutineType(types: !1111)
+!1111 = !{!1112, !1113}
+!1112 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !989, size: 64)
+!1113 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !990, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1114 = !DISubprogram(name: "_M_get_Tp_allocator", linkageName: "_ZNKSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_get_Tp_allocatorEv", scope: !990, file: !49, line: 241, type: !1115, isLocal: false, isDefinition: false, scopeLine: 241, flags: DIFlagPrototyped, isOptimized: true)
+!1115 = !DISubroutineType(types: !1116)
+!1116 = !{!1099, !1117}
+!1117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1118, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1118 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !990)
+!1119 = !DISubprogram(name: "get_allocator", linkageName: "_ZNKSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE13get_allocatorEv", scope: !990, file: !49, line: 245, type: !1120, isLocal: false, isDefinition: false, scopeLine: 245, flags: DIFlagPrototyped, isOptimized: true)
+!1120 = !DISubroutineType(types: !1121)
+!1121 = !{!1122, !1117}
+!1122 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !990, file: !49, line: 234, baseType: !1011)
+!1123 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 248, type: !1124, isLocal: false, isDefinition: false, scopeLine: 248, flags: DIFlagPrototyped, isOptimized: true)
+!1124 = !DISubroutineType(types: !1125)
+!1125 = !{null, !1113}
+!1126 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 251, type: !1127, isLocal: false, isDefinition: false, scopeLine: 251, flags: DIFlagPrototyped, isOptimized: true)
+!1127 = !DISubroutineType(types: !1128)
+!1128 = !{null, !1113, !1129}
+!1129 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1130, size: 64)
+!1130 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1122)
+!1131 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 254, type: !1132, isLocal: false, isDefinition: false, scopeLine: 254, flags: DIFlagPrototyped, isOptimized: true)
+!1132 = !DISubroutineType(types: !1133)
+!1133 = !{null, !1113, !175}
+!1134 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 258, type: !1135, isLocal: false, isDefinition: false, scopeLine: 258, flags: DIFlagPrototyped, isOptimized: true)
+!1135 = !DISubroutineType(types: !1136)
+!1136 = !{null, !1113, !175, !1129}
+!1137 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 263, type: !1138, isLocal: false, isDefinition: false, scopeLine: 263, flags: DIFlagPrototyped, isOptimized: true)
+!1138 = !DISubroutineType(types: !1139)
+!1139 = !{null, !1113, !1104}
+!1140 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 266, type: !1141, isLocal: false, isDefinition: false, scopeLine: 266, flags: DIFlagPrototyped, isOptimized: true)
+!1141 = !DISubroutineType(types: !1142)
+!1142 = !{null, !1113, !1143}
+!1143 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !990, size: 64)
+!1144 = !DISubprogram(name: "_Vector_base", scope: !990, file: !49, line: 270, type: !1145, isLocal: false, isDefinition: false, scopeLine: 270, flags: DIFlagPrototyped, isOptimized: true)
+!1145 = !DISubroutineType(types: !1146)
+!1146 = !{null, !1113, !1143, !1129}
+!1147 = !DISubprogram(name: "~_Vector_base", scope: !990, file: !49, line: 283, type: !1124, isLocal: false, isDefinition: false, scopeLine: 283, flags: DIFlagPrototyped, isOptimized: true)
+!1148 = !DISubprogram(name: "_M_allocate", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE11_M_allocateEm", scope: !990, file: !49, line: 293, type: !1149, isLocal: false, isDefinition: false, scopeLine: 293, flags: DIFlagPrototyped, isOptimized: true)
+!1149 = !DISubroutineType(types: !1150)
+!1150 = !{!997, !1113, !175}
+!1151 = !DISubprogram(name: "_M_deallocate", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE13_M_deallocateEPS5_m", scope: !990, file: !49, line: 300, type: !1152, isLocal: false, isDefinition: false, scopeLine: 300, flags: DIFlagPrototyped, isOptimized: true)
+!1152 = !DISubroutineType(types: !1153)
+!1153 = !{null, !1113, !997, !175}
+!1154 = !DISubprogram(name: "_M_create_storage", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE17_M_create_storageEm", scope: !990, file: !49, line: 309, type: !1132, isLocal: false, isDefinition: false, scopeLine: 309, flags: DIFlagPrivate | DIFlagPrototyped, isOptimized: true)
+!1155 = !{!602, !1075}
+!1156 = !DIDerivedType(tag: DW_TAG_typedef, name: "other", scope: !1157, file: !59, line: 117, baseType: !1158)
+!1157 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "rebind<std::__cxx11::basic_string<char> >", scope: !999, file: !59, line: 116, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !601, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEES6_E6rebindIS6_EE")
+!1158 = !DIDerivedType(tag: DW_TAG_typedef, name: "rebind_alloc<std::__cxx11::basic_string<char> >", scope: !1002, file: !64, line: 422, baseType: !1011)
+!1159 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !31, file: !30, line: 88, baseType: !1160)
+!1160 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !1161, file: !59, line: 61, baseType: !1184)
+!1161 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__alloc_traits<std::allocator<char>, char>", scope: !5, file: !59, line: 50, size: 8, flags: DIFlagTypePassByValue, elements: !1162, templateParams: !1206, identifier: "_ZTSN9__gnu_cxx14__alloc_traitsISaIcEcEE")
+!1162 = !{!1163, !1192, !1197, !1201, !1202, !1203, !1204, !1205}
+!1163 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !1161, baseType: !1164, extraData: i32 0)
+!1164 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "allocator_traits<std::allocator<char> >", scope: !13, file: !64, line: 384, size: 8, flags: DIFlagTypePassByValue, elements: !1165, templateParams: !1190, identifier: "_ZTSSt16allocator_traitsISaIcEE")
+!1165 = !{!1166, !1175, !1178, !1181, !1187}
+!1166 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaIcEE8allocateERS0_m", scope: !1164, file: !64, line: 435, type: !1167, isLocal: false, isDefinition: false, scopeLine: 435, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1167 = !DISubroutineType(types: !1168)
+!1168 = !{!1169, !1172, !198}
+!1169 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1164, file: !64, line: 392, baseType: !1170)
+!1170 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1171, size: 64)
+!1171 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+!1172 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1173, size: 64)
+!1173 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !1164, file: !64, line: 387, baseType: !1174)
+!1174 = !DICompositeType(tag: DW_TAG_class_type, name: "allocator<char>", scope: !13, file: !141, line: 199, flags: DIFlagFwdDecl, identifier: "_ZTSSaIcE")
+!1175 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaIcEE8allocateERS0_mPKv", scope: !1164, file: !64, line: 449, type: !1176, isLocal: false, isDefinition: false, scopeLine: 449, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1176 = !DISubroutineType(types: !1177)
+!1177 = !{!1169, !1172, !198, !202}
+!1178 = !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaIcEE10deallocateERS0_Pcm", scope: !1164, file: !64, line: 461, type: !1179, isLocal: false, isDefinition: false, scopeLine: 461, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1179 = !DISubroutineType(types: !1180)
+!1180 = !{null, !1172, !1169, !198}
+!1181 = !DISubprogram(name: "max_size", linkageName: "_ZNSt16allocator_traitsISaIcEE8max_sizeERKS0_", scope: !1164, file: !64, line: 495, type: !1182, isLocal: false, isDefinition: false, scopeLine: 495, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1182 = !DISubroutineType(types: !1183)
+!1183 = !{!1184, !1185}
+!1184 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !1164, file: !64, line: 407, baseType: !175)
+!1185 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1186, size: 64)
+!1186 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1173)
+!1187 = !DISubprogram(name: "select_on_container_copy_construction", linkageName: "_ZNSt16allocator_traitsISaIcEE37select_on_container_copy_constructionERKS0_", scope: !1164, file: !64, line: 504, type: !1188, isLocal: false, isDefinition: false, scopeLine: 504, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1188 = !DISubroutineType(types: !1189)
+!1189 = !{!1173, !1185}
+!1190 = !{!1191}
+!1191 = !DITemplateTypeParameter(name: "_Alloc", type: !1174)
+!1192 = !DISubprogram(name: "_S_select_on_copy", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE17_S_select_on_copyERKS1_", scope: !1161, file: !59, line: 94, type: !1193, isLocal: false, isDefinition: false, scopeLine: 94, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1193 = !DISubroutineType(types: !1194)
+!1194 = !{!1174, !1195}
+!1195 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1196, size: 64)
+!1196 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1174)
+!1197 = !DISubprogram(name: "_S_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE10_S_on_swapERS1_S3_", scope: !1161, file: !59, line: 97, type: !1198, isLocal: false, isDefinition: false, scopeLine: 97, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1198 = !DISubroutineType(types: !1199)
+!1199 = !{null, !1200, !1200}
+!1200 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1174, size: 64)
+!1201 = !DISubprogram(name: "_S_propagate_on_copy_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE27_S_propagate_on_copy_assignEv", scope: !1161, file: !59, line: 100, type: !225, isLocal: false, isDefinition: false, scopeLine: 100, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1202 = !DISubprogram(name: "_S_propagate_on_move_assign", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE27_S_propagate_on_move_assignEv", scope: !1161, file: !59, line: 103, type: !225, isLocal: false, isDefinition: false, scopeLine: 103, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1203 = !DISubprogram(name: "_S_propagate_on_swap", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE20_S_propagate_on_swapEv", scope: !1161, file: !59, line: 106, type: !225, isLocal: false, isDefinition: false, scopeLine: 106, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1204 = !DISubprogram(name: "_S_always_equal", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE15_S_always_equalEv", scope: !1161, file: !59, line: 109, type: !225, isLocal: false, isDefinition: false, scopeLine: 109, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1205 = !DISubprogram(name: "_S_nothrow_move", linkageName: "_ZN9__gnu_cxx14__alloc_traitsISaIcEcE15_S_nothrow_moveEv", scope: !1161, file: !59, line: 112, type: !225, isLocal: false, isDefinition: false, scopeLine: 112, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1206 = !{!1191, !1207}
+!1207 = !DITemplateTypeParameter(type: !1171)
+!1208 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1209, size: 64)
+!1209 = !DIDerivedType(tag: DW_TAG_typedef, name: "char_type", scope: !1211, file: !1210, line: 277, baseType: !1171)
+!1210 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/char_traits.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1211 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "char_traits<char>", scope: !13, file: !1210, line: 275, size: 8, flags: DIFlagTypePassByValue, elements: !1212, templateParams: !1258, identifier: "_ZTSSt11char_traitsIcE")
+!1212 = !{!1213, !1219, !1222, !1223, !1227, !1230, !1233, !1236, !1237, !1240, !1246, !1249, !1252, !1255}
+!1213 = !DISubprogram(name: "assign", linkageName: "_ZNSt11char_traitsIcE6assignERcRKc", scope: !1211, file: !1210, line: 284, type: !1214, isLocal: false, isDefinition: false, scopeLine: 284, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1214 = !DISubroutineType(types: !1215)
+!1215 = !{null, !1216, !1217}
+!1216 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1209, size: 64)
+!1217 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1218, size: 64)
+!1218 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1209)
+!1219 = !DISubprogram(name: "eq", linkageName: "_ZNSt11char_traitsIcE2eqERKcS2_", scope: !1211, file: !1210, line: 288, type: !1220, isLocal: false, isDefinition: false, scopeLine: 288, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1220 = !DISubroutineType(types: !1221)
+!1221 = !{!117, !1217, !1217}
+!1222 = !DISubprogram(name: "lt", linkageName: "_ZNSt11char_traitsIcE2ltERKcS2_", scope: !1211, file: !1210, line: 292, type: !1220, isLocal: false, isDefinition: false, scopeLine: 292, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1223 = !DISubprogram(name: "compare", linkageName: "_ZNSt11char_traitsIcE7compareEPKcS2_m", scope: !1211, file: !1210, line: 300, type: !1224, isLocal: false, isDefinition: false, scopeLine: 300, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1224 = !DISubroutineType(types: !1225)
+!1225 = !{!93, !1226, !1226, !175}
+!1226 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1218, size: 64)
+!1227 = !DISubprogram(name: "length", linkageName: "_ZNSt11char_traitsIcE6lengthEPKc", scope: !1211, file: !1210, line: 314, type: !1228, isLocal: false, isDefinition: false, scopeLine: 314, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1228 = !DISubroutineType(types: !1229)
+!1229 = !{!175, !1226}
+!1230 = !DISubprogram(name: "find", linkageName: "_ZNSt11char_traitsIcE4findEPKcmRS1_", scope: !1211, file: !1210, line: 324, type: !1231, isLocal: false, isDefinition: false, scopeLine: 324, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1231 = !DISubroutineType(types: !1232)
+!1232 = !{!1226, !1226, !175, !1217}
+!1233 = !DISubprogram(name: "move", linkageName: "_ZNSt11char_traitsIcE4moveEPcPKcm", scope: !1211, file: !1210, line: 338, type: !1234, isLocal: false, isDefinition: false, scopeLine: 338, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1234 = !DISubroutineType(types: !1235)
+!1235 = !{!1208, !1208, !1226, !175}
+!1236 = !DISubprogram(name: "copy", linkageName: "_ZNSt11char_traitsIcE4copyEPcPKcm", scope: !1211, file: !1210, line: 346, type: !1234, isLocal: false, isDefinition: false, scopeLine: 346, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1237 = !DISubprogram(name: "assign", linkageName: "_ZNSt11char_traitsIcE6assignEPcmc", scope: !1211, file: !1210, line: 354, type: !1238, isLocal: false, isDefinition: false, scopeLine: 354, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1238 = !DISubroutineType(types: !1239)
+!1239 = !{!1208, !1208, !175, !1209}
+!1240 = !DISubprogram(name: "to_char_type", linkageName: "_ZNSt11char_traitsIcE12to_char_typeERKi", scope: !1211, file: !1210, line: 362, type: !1241, isLocal: false, isDefinition: false, scopeLine: 362, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1241 = !DISubroutineType(types: !1242)
+!1242 = !{!1209, !1243}
+!1243 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1244, size: 64)
+!1244 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1245)
+!1245 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_type", scope: !1211, file: !1210, line: 278, baseType: !93)
+!1246 = !DISubprogram(name: "to_int_type", linkageName: "_ZNSt11char_traitsIcE11to_int_typeERKc", scope: !1211, file: !1210, line: 368, type: !1247, isLocal: false, isDefinition: false, scopeLine: 368, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1247 = !DISubroutineType(types: !1248)
+!1248 = !{!1245, !1217}
+!1249 = !DISubprogram(name: "eq_int_type", linkageName: "_ZNSt11char_traitsIcE11eq_int_typeERKiS2_", scope: !1211, file: !1210, line: 372, type: !1250, isLocal: false, isDefinition: false, scopeLine: 372, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1250 = !DISubroutineType(types: !1251)
+!1251 = !{!117, !1243, !1243}
+!1252 = !DISubprogram(name: "eof", linkageName: "_ZNSt11char_traitsIcE3eofEv", scope: !1211, file: !1210, line: 376, type: !1253, isLocal: false, isDefinition: false, scopeLine: 376, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1253 = !DISubroutineType(types: !1254)
+!1254 = !{!1245}
+!1255 = !DISubprogram(name: "not_eof", linkageName: "_ZNSt11char_traitsIcE7not_eofERKi", scope: !1211, file: !1210, line: 380, type: !1256, isLocal: false, isDefinition: false, scopeLine: 380, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!1256 = !DISubroutineType(types: !1257)
+!1257 = !{!1245, !1243}
+!1258 = !{!1259}
+!1259 = !DITemplateTypeParameter(name: "_CharT", type: !1171)
+!1260 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", file: !49, line: 374, baseType: !175)
+!1261 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !243, size: 64)
+!1262 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator", scope: !1263, file: !49, line: 369, baseType: !1461)
+!1263 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >", scope: !13, file: !49, line: 339, size: 192, flags: DIFlagTypePassByReference, elements: !1264, templateParams: !298, identifier: "_ZTSSt6vectorISt4pairIiiESaIS1_EE")
+!1264 = !{!1265, !1266, !1270, !1276, !1279, !1285, !1290, !1294, !1297, !1300, !1305, !1306, !1310, !1313, !1316, !1319, !1322, !1325, !1331, !1332, !1333, !1338, !1343, !1344, !1345, !1346, !1347, !1348, !1349, !1352, !1353, !1356, !1357, !1358, !1359, !1362, !1363, !1371, !1378, !1381, !1382, !1383, !1386, !1389, !1390, !1391, !1394, !1397, !1400, !1404, !1405, !1408, !1411, !1414, !1417, !1420, !1423, !1426, !1427, !1428, !1429, !1430, !1433, !1434, !1437, !1438, !1439, !1445, !1449, !1452, !1455, !1458}
+!1265 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !1263, baseType: !50, flags: DIFlagProtected, extraData: i32 0)
+!1266 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 391, type: !1267, isLocal: false, isDefinition: false, scopeLine: 391, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1267 = !DISubroutineType(types: !1268)
+!1268 = !{null, !1269}
+!1269 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1263, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1270 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 402, type: !1271, isLocal: false, isDefinition: false, scopeLine: 402, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1271 = !DISubroutineType(types: !1272)
+!1272 = !{null, !1269, !1273}
+!1273 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1274, size: 64)
+!1274 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1275)
+!1275 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !1263, file: !49, line: 376, baseType: !140)
+!1276 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 415, type: !1277, isLocal: false, isDefinition: false, scopeLine: 415, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1277 = !DISubroutineType(types: !1278)
+!1278 = !{null, !1269, !1260, !1273}
+!1279 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 427, type: !1280, isLocal: false, isDefinition: false, scopeLine: 427, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1280 = !DISubroutineType(types: !1281)
+!1281 = !{null, !1269, !1260, !1282, !1273}
+!1282 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1283, size: 64)
+!1283 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1284)
+!1284 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !1263, file: !49, line: 364, baseType: !71)
+!1285 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 458, type: !1286, isLocal: false, isDefinition: false, scopeLine: 458, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1286 = !DISubroutineType(types: !1287)
+!1287 = !{null, !1269, !1288}
+!1288 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1289, size: 64)
+!1289 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1263)
+!1290 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 476, type: !1291, isLocal: false, isDefinition: false, scopeLine: 476, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1291 = !DISubroutineType(types: !1292)
+!1292 = !{null, !1269, !1293}
+!1293 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !1263, size: 64)
+!1294 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 480, type: !1295, isLocal: false, isDefinition: false, scopeLine: 480, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1295 = !DISubroutineType(types: !1296)
+!1296 = !{null, !1269, !1288, !1273}
+!1297 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 490, type: !1298, isLocal: false, isDefinition: false, scopeLine: 490, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1298 = !DISubroutineType(types: !1299)
+!1299 = !{null, !1269, !1293, !1273}
+!1300 = !DISubprogram(name: "vector", scope: !1263, file: !49, line: 515, type: !1301, isLocal: false, isDefinition: false, scopeLine: 515, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1301 = !DISubroutineType(types: !1302)
+!1302 = !{null, !1269, !1303, !1273}
+!1303 = !DICompositeType(tag: DW_TAG_class_type, name: "initializer_list<std::pair<int, int> >", scope: !13, file: !1304, line: 47, flags: DIFlagFwdDecl, identifier: "_ZTSSt16initializer_listISt4pairIiiEE")
+!1304 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/initializer_list", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1305 = !DISubprogram(name: "~vector", scope: !1263, file: !49, line: 565, type: !1267, isLocal: false, isDefinition: false, scopeLine: 565, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1306 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EEaSERKS3_", scope: !1263, file: !49, line: 582, type: !1307, isLocal: false, isDefinition: false, scopeLine: 582, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1307 = !DISubroutineType(types: !1308)
+!1308 = !{!1309, !1269, !1288}
+!1309 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1263, size: 64)
+!1310 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EEaSEOS3_", scope: !1263, file: !49, line: 596, type: !1311, isLocal: false, isDefinition: false, scopeLine: 596, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1311 = !DISubroutineType(types: !1312)
+!1312 = !{!1309, !1269, !1293}
+!1313 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EEaSESt16initializer_listIS1_E", scope: !1263, file: !49, line: 617, type: !1314, isLocal: false, isDefinition: false, scopeLine: 617, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1314 = !DISubroutineType(types: !1315)
+!1315 = !{!1309, !1269, !1303}
+!1316 = !DISubprogram(name: "assign", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6assignEmRKS1_", scope: !1263, file: !49, line: 636, type: !1317, isLocal: false, isDefinition: false, scopeLine: 636, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1317 = !DISubroutineType(types: !1318)
+!1318 = !{null, !1269, !1260, !1282}
+!1319 = !DISubprogram(name: "assign", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6assignESt16initializer_listIS1_E", scope: !1263, file: !49, line: 681, type: !1320, isLocal: false, isDefinition: false, scopeLine: 681, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1320 = !DISubroutineType(types: !1321)
+!1321 = !{null, !1269, !1303}
+!1322 = !DISubprogram(name: "begin", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE5beginEv", scope: !1263, file: !49, line: 698, type: !1323, isLocal: false, isDefinition: false, scopeLine: 698, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1323 = !DISubroutineType(types: !1324)
+!1324 = !{!1262, !1269}
+!1325 = !DISubprogram(name: "begin", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE5beginEv", scope: !1263, file: !49, line: 707, type: !1326, isLocal: false, isDefinition: false, scopeLine: 707, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1326 = !DISubroutineType(types: !1327)
+!1327 = !{!1328, !1330}
+!1328 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_iterator", scope: !1263, file: !49, line: 371, baseType: !1329)
+!1329 = !DICompositeType(tag: DW_TAG_class_type, name: "__normal_iterator<const std::pair<int, int> *, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >", scope: !5, file: !879, line: 764, flags: DIFlagFwdDecl, identifier: "_ZTSN9__gnu_cxx17__normal_iteratorIPKSt4pairIiiESt6vectorIS2_SaIS2_EEEE")
+!1330 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1289, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1331 = !DISubprogram(name: "end", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE3endEv", scope: !1263, file: !49, line: 716, type: !1323, isLocal: false, isDefinition: false, scopeLine: 716, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1332 = !DISubprogram(name: "end", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE3endEv", scope: !1263, file: !49, line: 725, type: !1326, isLocal: false, isDefinition: false, scopeLine: 725, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1333 = !DISubprogram(name: "rbegin", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6rbeginEv", scope: !1263, file: !49, line: 734, type: !1334, isLocal: false, isDefinition: false, scopeLine: 734, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1334 = !DISubroutineType(types: !1335)
+!1335 = !{!1336, !1269}
+!1336 = !DIDerivedType(tag: DW_TAG_typedef, name: "reverse_iterator", scope: !1263, file: !49, line: 373, baseType: !1337)
+!1337 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<__gnu_cxx::__normal_iterator<std::pair<int, int> *, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS3_SaIS3_EEEEE")
+!1338 = !DISubprogram(name: "rbegin", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE6rbeginEv", scope: !1263, file: !49, line: 743, type: !1339, isLocal: false, isDefinition: false, scopeLine: 743, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1339 = !DISubroutineType(types: !1340)
+!1340 = !{!1341, !1330}
+!1341 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reverse_iterator", scope: !1263, file: !49, line: 372, baseType: !1342)
+!1342 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<__gnu_cxx::__normal_iterator<const std::pair<int, int> *, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPKSt4pairIiiESt6vectorIS3_SaIS3_EEEEE")
+!1343 = !DISubprogram(name: "rend", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE4rendEv", scope: !1263, file: !49, line: 752, type: !1334, isLocal: false, isDefinition: false, scopeLine: 752, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1344 = !DISubprogram(name: "rend", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4rendEv", scope: !1263, file: !49, line: 761, type: !1339, isLocal: false, isDefinition: false, scopeLine: 761, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1345 = !DISubprogram(name: "cbegin", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE6cbeginEv", scope: !1263, file: !49, line: 771, type: !1326, isLocal: false, isDefinition: false, scopeLine: 771, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1346 = !DISubprogram(name: "cend", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4cendEv", scope: !1263, file: !49, line: 780, type: !1326, isLocal: false, isDefinition: false, scopeLine: 780, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1347 = !DISubprogram(name: "crbegin", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE7crbeginEv", scope: !1263, file: !49, line: 789, type: !1339, isLocal: false, isDefinition: false, scopeLine: 789, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1348 = !DISubprogram(name: "crend", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE5crendEv", scope: !1263, file: !49, line: 798, type: !1339, isLocal: false, isDefinition: false, scopeLine: 798, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1349 = !DISubprogram(name: "size", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4sizeEv", scope: !1263, file: !49, line: 805, type: !1350, isLocal: false, isDefinition: false, scopeLine: 805, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1350 = !DISubroutineType(types: !1351)
+!1351 = !{!1260, !1330}
+!1352 = !DISubprogram(name: "max_size", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE8max_sizeEv", scope: !1263, file: !49, line: 810, type: !1350, isLocal: false, isDefinition: false, scopeLine: 810, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1353 = !DISubprogram(name: "resize", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6resizeEm", scope: !1263, file: !49, line: 824, type: !1354, isLocal: false, isDefinition: false, scopeLine: 824, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1354 = !DISubroutineType(types: !1355)
+!1355 = !{null, !1269, !1260}
+!1356 = !DISubprogram(name: "resize", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6resizeEmRKS1_", scope: !1263, file: !49, line: 844, type: !1317, isLocal: false, isDefinition: false, scopeLine: 844, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1357 = !DISubprogram(name: "shrink_to_fit", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE13shrink_to_fitEv", scope: !1263, file: !49, line: 876, type: !1267, isLocal: false, isDefinition: false, scopeLine: 876, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1358 = !DISubprogram(name: "capacity", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE8capacityEv", scope: !1263, file: !49, line: 885, type: !1350, isLocal: false, isDefinition: false, scopeLine: 885, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1359 = !DISubprogram(name: "empty", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE5emptyEv", scope: !1263, file: !49, line: 894, type: !1360, isLocal: false, isDefinition: false, scopeLine: 894, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1360 = !DISubroutineType(types: !1361)
+!1361 = !{!117, !1330}
+!1362 = !DISubprogram(name: "reserve", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE7reserveEm", scope: !1263, file: !49, line: 915, type: !1354, isLocal: false, isDefinition: false, scopeLine: 915, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1363 = !DISubprogram(name: "operator[]", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EEixEm", scope: !1263, file: !49, line: 930, type: !1364, isLocal: false, isDefinition: false, scopeLine: 930, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1364 = !DISubroutineType(types: !1365)
+!1365 = !{!1366, !1269, !1260}
+!1366 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !1263, file: !49, line: 367, baseType: !1367)
+!1367 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !60, file: !59, line: 64, baseType: !1368)
+!1368 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1369, size: 64)
+!1369 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !60, file: !59, line: 58, baseType: !1370)
+!1370 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !63, file: !64, line: 389, baseType: !71)
+!1371 = !DISubprogram(name: "operator[]", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EEixEm", scope: !1263, file: !49, line: 948, type: !1372, isLocal: false, isDefinition: false, scopeLine: 948, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1372 = !DISubroutineType(types: !1373)
+!1373 = !{!1374, !1330, !1260}
+!1374 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !1263, file: !49, line: 368, baseType: !1375)
+!1375 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !60, file: !59, line: 65, baseType: !1376)
+!1376 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1377, size: 64)
+!1377 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1369)
+!1378 = !DISubprogram(name: "_M_range_check", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE14_M_range_checkEm", scope: !1263, file: !49, line: 957, type: !1379, isLocal: false, isDefinition: false, scopeLine: 957, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1379 = !DISubroutineType(types: !1380)
+!1380 = !{null, !1330, !1260}
+!1381 = !DISubprogram(name: "at", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE2atEm", scope: !1263, file: !49, line: 979, type: !1364, isLocal: false, isDefinition: false, scopeLine: 979, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1382 = !DISubprogram(name: "at", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE2atEm", scope: !1263, file: !49, line: 997, type: !1372, isLocal: false, isDefinition: false, scopeLine: 997, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1383 = !DISubprogram(name: "front", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE5frontEv", scope: !1263, file: !49, line: 1008, type: !1384, isLocal: false, isDefinition: false, scopeLine: 1008, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1384 = !DISubroutineType(types: !1385)
+!1385 = !{!1366, !1269}
+!1386 = !DISubprogram(name: "front", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE5frontEv", scope: !1263, file: !49, line: 1019, type: !1387, isLocal: false, isDefinition: false, scopeLine: 1019, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1387 = !DISubroutineType(types: !1388)
+!1388 = !{!1374, !1330}
+!1389 = !DISubprogram(name: "back", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE4backEv", scope: !1263, file: !49, line: 1030, type: !1384, isLocal: false, isDefinition: false, scopeLine: 1030, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1390 = !DISubprogram(name: "back", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4backEv", scope: !1263, file: !49, line: 1041, type: !1387, isLocal: false, isDefinition: false, scopeLine: 1041, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1391 = !DISubprogram(name: "data", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE4dataEv", scope: !1263, file: !49, line: 1055, type: !1392, isLocal: false, isDefinition: false, scopeLine: 1055, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1392 = !DISubroutineType(types: !1393)
+!1393 = !{!70, !1269}
+!1394 = !DISubprogram(name: "data", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4dataEv", scope: !1263, file: !49, line: 1059, type: !1395, isLocal: false, isDefinition: false, scopeLine: 1059, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1395 = !DISubroutineType(types: !1396)
+!1396 = !{!169, !1330}
+!1397 = !DISubprogram(name: "push_back", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE9push_backERKS1_", scope: !1263, file: !49, line: 1074, type: !1398, isLocal: false, isDefinition: false, scopeLine: 1074, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1398 = !DISubroutineType(types: !1399)
+!1399 = !{null, !1269, !1282}
+!1400 = !DISubprogram(name: "push_back", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE9push_backEOS1_", scope: !1263, file: !49, line: 1090, type: !1401, isLocal: false, isDefinition: false, scopeLine: 1090, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1401 = !DISubroutineType(types: !1402)
+!1402 = !{null, !1269, !1403}
+!1403 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !1284, size: 64)
+!1404 = !DISubprogram(name: "pop_back", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE8pop_backEv", scope: !1263, file: !49, line: 1112, type: !1267, isLocal: false, isDefinition: false, scopeLine: 1112, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1405 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EERS6_", scope: !1263, file: !49, line: 1150, type: !1406, isLocal: false, isDefinition: false, scopeLine: 1150, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1406 = !DISubroutineType(types: !1407)
+!1407 = !{!1262, !1269, !1328, !1282}
+!1408 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEOS1_", scope: !1263, file: !49, line: 1180, type: !1409, isLocal: false, isDefinition: false, scopeLine: 1180, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1409 = !DISubroutineType(types: !1410)
+!1410 = !{!1262, !1269, !1328, !1403}
+!1411 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EESt16initializer_listIS1_E", scope: !1263, file: !49, line: 1197, type: !1412, isLocal: false, isDefinition: false, scopeLine: 1197, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1412 = !DISubroutineType(types: !1413)
+!1413 = !{!1262, !1269, !1328, !1303}
+!1414 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEmRS6_", scope: !1263, file: !49, line: 1222, type: !1415, isLocal: false, isDefinition: false, scopeLine: 1222, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1415 = !DISubroutineType(types: !1416)
+!1416 = !{!1262, !1269, !1328, !1260, !1282}
+!1417 = !DISubprogram(name: "erase", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE5eraseEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EE", scope: !1263, file: !49, line: 1317, type: !1418, isLocal: false, isDefinition: false, scopeLine: 1317, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1418 = !DISubroutineType(types: !1419)
+!1419 = !{!1262, !1269, !1328}
+!1420 = !DISubprogram(name: "erase", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE5eraseEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EES8_", scope: !1263, file: !49, line: 1344, type: !1421, isLocal: false, isDefinition: false, scopeLine: 1344, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1421 = !DISubroutineType(types: !1422)
+!1422 = !{!1262, !1269, !1328, !1328}
+!1423 = !DISubprogram(name: "swap", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE4swapERS3_", scope: !1263, file: !49, line: 1367, type: !1424, isLocal: false, isDefinition: false, scopeLine: 1367, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1424 = !DISubroutineType(types: !1425)
+!1425 = !{null, !1269, !1309}
+!1426 = !DISubprogram(name: "clear", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE5clearEv", scope: !1263, file: !49, line: 1385, type: !1267, isLocal: false, isDefinition: false, scopeLine: 1385, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1427 = !DISubprogram(name: "_M_fill_initialize", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE18_M_fill_initializeEmRKS1_", scope: !1263, file: !49, line: 1477, type: !1317, isLocal: false, isDefinition: false, scopeLine: 1477, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1428 = !DISubprogram(name: "_M_default_initialize", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE21_M_default_initializeEm", scope: !1263, file: !49, line: 1487, type: !1354, isLocal: false, isDefinition: false, scopeLine: 1487, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1429 = !DISubprogram(name: "_M_fill_assign", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_fill_assignEmRKS1_", scope: !1263, file: !49, line: 1529, type: !1317, isLocal: false, isDefinition: false, scopeLine: 1529, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1430 = !DISubprogram(name: "_M_fill_insert", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_fill_insertEN9__gnu_cxx17__normal_iteratorIPS1_S3_EEmRKS1_", scope: !1263, file: !49, line: 1568, type: !1431, isLocal: false, isDefinition: false, scopeLine: 1568, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1431 = !DISubroutineType(types: !1432)
+!1432 = !{null, !1269, !1262, !1260, !1282}
+!1433 = !DISubprogram(name: "_M_default_append", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_default_appendEm", scope: !1263, file: !49, line: 1573, type: !1354, isLocal: false, isDefinition: false, scopeLine: 1573, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1434 = !DISubprogram(name: "_M_shrink_to_fit", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE16_M_shrink_to_fitEv", scope: !1263, file: !49, line: 1576, type: !1435, isLocal: false, isDefinition: false, scopeLine: 1576, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1435 = !DISubroutineType(types: !1436)
+!1436 = !{!117, !1269}
+!1437 = !DISubprogram(name: "_M_insert_rval", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_insert_rvalEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEOS1_", scope: !1263, file: !49, line: 1625, type: !1409, isLocal: false, isDefinition: false, scopeLine: 1625, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1438 = !DISubprogram(name: "_M_emplace_aux", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_emplace_auxEN9__gnu_cxx17__normal_iteratorIPKS1_S3_EEOS1_", scope: !1263, file: !49, line: 1634, type: !1409, isLocal: false, isDefinition: false, scopeLine: 1634, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1439 = !DISubprogram(name: "_M_check_len", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE12_M_check_lenEmPKc", scope: !1263, file: !49, line: 1640, type: !1440, isLocal: false, isDefinition: false, scopeLine: 1640, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1440 = !DISubroutineType(types: !1441)
+!1441 = !{!1442, !1330, !1260, !1443}
+!1442 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !1263, file: !49, line: 374, baseType: !175)
+!1443 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1444, size: 64)
+!1444 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1171)
+!1445 = !DISubprogram(name: "_M_erase_at_end", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE15_M_erase_at_endEPS1_", scope: !1263, file: !49, line: 1654, type: !1446, isLocal: false, isDefinition: false, scopeLine: 1654, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1446 = !DISubroutineType(types: !1447)
+!1447 = !{null, !1269, !1448}
+!1448 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1263, file: !49, line: 365, baseType: !57)
+!1449 = !DISubprogram(name: "_M_erase", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS1_S3_EE", scope: !1263, file: !49, line: 1666, type: !1450, isLocal: false, isDefinition: false, scopeLine: 1666, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1450 = !DISubroutineType(types: !1451)
+!1451 = !{!1262, !1269, !1262}
+!1452 = !DISubprogram(name: "_M_erase", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS1_S3_EES7_", scope: !1263, file: !49, line: 1669, type: !1453, isLocal: false, isDefinition: false, scopeLine: 1669, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!1453 = !DISubroutineType(types: !1454)
+!1454 = !{!1262, !1269, !1262, !1262}
+!1455 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_move_assignEOS3_St17integral_constantIbLb1EE", scope: !1263, file: !49, line: 1677, type: !1456, isLocal: false, isDefinition: false, scopeLine: 1677, flags: DIFlagPrototyped, isOptimized: true)
+!1456 = !DISubroutineType(types: !1457)
+!1457 = !{null, !1269, !1293, !950}
+!1458 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE14_M_move_assignEOS3_St17integral_constantIbLb0EE", scope: !1263, file: !49, line: 1688, type: !1459, isLocal: false, isDefinition: false, scopeLine: 1688, flags: DIFlagPrototyped, isOptimized: true)
+!1459 = !DISubroutineType(types: !1460)
+!1460 = !{null, !1269, !1293, !968}
+!1461 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "__normal_iterator<std::pair<int, int> *, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >", scope: !5, file: !879, line: 764, size: 64, flags: DIFlagTypePassByValue, elements: !1462, templateParams: !1516, identifier: "_ZTSN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEE")
+!1462 = !{!1463, !1464, !1468, !1473, !1484, !1489, !1493, !1496, !1497, !1498, !1505, !1508, !1511, !1512, !1513}
+!1463 = !DIDerivedType(tag: DW_TAG_member, name: "_M_current", scope: !1461, file: !879, line: 767, baseType: !70, size: 64, flags: DIFlagProtected)
+!1464 = !DISubprogram(name: "__normal_iterator", scope: !1461, file: !879, line: 779, type: !1465, isLocal: false, isDefinition: false, scopeLine: 779, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1465 = !DISubroutineType(types: !1466)
+!1466 = !{null, !1467}
+!1467 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1461, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1468 = !DISubprogram(name: "__normal_iterator", scope: !1461, file: !879, line: 783, type: !1469, isLocal: false, isDefinition: false, scopeLine: 783, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1469 = !DISubroutineType(types: !1470)
+!1470 = !{null, !1467, !1471}
+!1471 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1472, size: 64)
+!1472 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !70)
+!1473 = !DISubprogram(name: "operator*", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEdeEv", scope: !1461, file: !879, line: 796, type: !1474, isLocal: false, isDefinition: false, scopeLine: 796, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1474 = !DISubroutineType(types: !1475)
+!1475 = !{!1476, !1482}
+!1476 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !1461, file: !879, line: 776, baseType: !1477)
+!1477 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !1479, file: !1478, line: 184, baseType: !110)
+!1478 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_iterator_base_types.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1479 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "iterator_traits<std::pair<int, int> *>", scope: !13, file: !1478, line: 178, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !1480, identifier: "_ZTSSt15iterator_traitsIPSt4pairIiiEE")
+!1480 = !{!1481}
+!1481 = !DITemplateTypeParameter(name: "_Iterator", type: !70)
+!1482 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1483, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1483 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1461)
+!1484 = !DISubprogram(name: "operator->", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEptEv", scope: !1461, file: !879, line: 800, type: !1485, isLocal: false, isDefinition: false, scopeLine: 800, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1485 = !DISubroutineType(types: !1486)
+!1486 = !{!1487, !1482}
+!1487 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1461, file: !879, line: 777, baseType: !1488)
+!1488 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1479, file: !1478, line: 183, baseType: !70)
+!1489 = !DISubprogram(name: "operator++", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEppEv", scope: !1461, file: !879, line: 804, type: !1490, isLocal: false, isDefinition: false, scopeLine: 804, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1490 = !DISubroutineType(types: !1491)
+!1491 = !{!1492, !1467}
+!1492 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1461, size: 64)
+!1493 = !DISubprogram(name: "operator++", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEppEi", scope: !1461, file: !879, line: 811, type: !1494, isLocal: false, isDefinition: false, scopeLine: 811, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1494 = !DISubroutineType(types: !1495)
+!1495 = !{!1461, !1467, !93}
+!1496 = !DISubprogram(name: "operator--", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEmmEv", scope: !1461, file: !879, line: 816, type: !1490, isLocal: false, isDefinition: false, scopeLine: 816, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1497 = !DISubprogram(name: "operator--", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEmmEi", scope: !1461, file: !879, line: 823, type: !1494, isLocal: false, isDefinition: false, scopeLine: 823, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1498 = !DISubprogram(name: "operator[]", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEixEl", scope: !1461, file: !879, line: 828, type: !1499, isLocal: false, isDefinition: false, scopeLine: 828, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1499 = !DISubroutineType(types: !1500)
+!1500 = !{!1476, !1482, !1501}
+!1501 = !DIDerivedType(tag: DW_TAG_typedef, name: "difference_type", scope: !1461, file: !879, line: 775, baseType: !1502)
+!1502 = !DIDerivedType(tag: DW_TAG_typedef, name: "difference_type", scope: !1479, file: !1478, line: 182, baseType: !1503)
+!1503 = !DIDerivedType(tag: DW_TAG_typedef, name: "ptrdiff_t", scope: !13, file: !176, line: 239, baseType: !1504)
+!1504 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed)
+!1505 = !DISubprogram(name: "operator+=", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEpLEl", scope: !1461, file: !879, line: 832, type: !1506, isLocal: false, isDefinition: false, scopeLine: 832, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1506 = !DISubroutineType(types: !1507)
+!1507 = !{!1492, !1467, !1501}
+!1508 = !DISubprogram(name: "operator+", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEplEl", scope: !1461, file: !879, line: 836, type: !1509, isLocal: false, isDefinition: false, scopeLine: 836, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1509 = !DISubroutineType(types: !1510)
+!1510 = !{!1461, !1482, !1501}
+!1511 = !DISubprogram(name: "operator-=", linkageName: "_ZN9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEmIEl", scope: !1461, file: !879, line: 840, type: !1506, isLocal: false, isDefinition: false, scopeLine: 840, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1512 = !DISubprogram(name: "operator-", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEEmiEl", scope: !1461, file: !879, line: 844, type: !1509, isLocal: false, isDefinition: false, scopeLine: 844, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1513 = !DISubprogram(name: "base", linkageName: "_ZNK9__gnu_cxx17__normal_iteratorIPSt4pairIiiESt6vectorIS2_SaIS2_EEE4baseEv", scope: !1461, file: !879, line: 848, type: !1514, isLocal: false, isDefinition: false, scopeLine: 848, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1514 = !DISubroutineType(types: !1515)
+!1515 = !{!1471, !1482}
+!1516 = !{!1481, !1517}
+!1517 = !DITemplateTypeParameter(name: "_Container", type: !1263)
+!1518 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "move_iterator<std::pair<int, int> *>", scope: !13, file: !879, line: 1007, size: 64, flags: DIFlagTypePassByValue, elements: !1519, templateParams: !1480, identifier: "_ZTSSt13move_iteratorIPSt4pairIiiEE")
+!1519 = !{!1520, !1521, !1525, !1529, !1534, !1542, !1546, !1550, !1553, !1554, !1555, !1559, !1562, !1563, !1564}
+!1520 = !DIDerivedType(tag: DW_TAG_member, name: "_M_current", scope: !1518, file: !879, line: 1010, baseType: !70, size: 64, flags: DIFlagProtected)
+!1521 = !DISubprogram(name: "move_iterator", scope: !1518, file: !879, line: 1029, type: !1522, isLocal: false, isDefinition: false, scopeLine: 1029, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1522 = !DISubroutineType(types: !1523)
+!1523 = !{null, !1524}
+!1524 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1518, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1525 = !DISubprogram(name: "move_iterator", scope: !1518, file: !879, line: 1033, type: !1526, isLocal: false, isDefinition: false, scopeLine: 1033, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1526 = !DISubroutineType(types: !1527)
+!1527 = !{null, !1524, !1528}
+!1528 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator_type", scope: !1518, file: !879, line: 1016, baseType: !70)
+!1529 = !DISubprogram(name: "base", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEE4baseEv", scope: !1518, file: !879, line: 1042, type: !1530, isLocal: false, isDefinition: false, scopeLine: 1042, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1530 = !DISubroutineType(types: !1531)
+!1531 = !{!1528, !1532}
+!1532 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1533, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1533 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1518)
+!1534 = !DISubprogram(name: "operator*", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEEdeEv", scope: !1518, file: !879, line: 1046, type: !1535, isLocal: false, isDefinition: false, scopeLine: 1046, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1535 = !DISubroutineType(types: !1536)
+!1536 = !{!1537, !1532}
+!1537 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !1518, file: !879, line: 1026, baseType: !1538)
+!1538 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !1539, file: !112, line: 1970, baseType: !106)
+!1539 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "conditional<true, std::pair<int, int> &&, std::pair<int, int> &>", scope: !13, file: !112, line: 1969, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !1540, identifier: "_ZTSSt11conditionalILb1EOSt4pairIiiERS1_E")
+!1540 = !{!116, !129, !1541}
+!1541 = !DITemplateTypeParameter(name: "_Iffalse", type: !110)
+!1542 = !DISubprogram(name: "operator->", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEEptEv", scope: !1518, file: !879, line: 1050, type: !1543, isLocal: false, isDefinition: false, scopeLine: 1050, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1543 = !DISubroutineType(types: !1544)
+!1544 = !{!1545, !1532}
+!1545 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !1518, file: !879, line: 1021, baseType: !70)
+!1546 = !DISubprogram(name: "operator++", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEppEv", scope: !1518, file: !879, line: 1054, type: !1547, isLocal: false, isDefinition: false, scopeLine: 1054, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1547 = !DISubroutineType(types: !1548)
+!1548 = !{!1549, !1524}
+!1549 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1518, size: 64)
+!1550 = !DISubprogram(name: "operator++", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEppEi", scope: !1518, file: !879, line: 1061, type: !1551, isLocal: false, isDefinition: false, scopeLine: 1061, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1551 = !DISubroutineType(types: !1552)
+!1552 = !{!1518, !1524, !93}
+!1553 = !DISubprogram(name: "operator--", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEmmEv", scope: !1518, file: !879, line: 1069, type: !1547, isLocal: false, isDefinition: false, scopeLine: 1069, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1554 = !DISubprogram(name: "operator--", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEmmEi", scope: !1518, file: !879, line: 1076, type: !1551, isLocal: false, isDefinition: false, scopeLine: 1076, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1555 = !DISubprogram(name: "operator+", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEEplEl", scope: !1518, file: !879, line: 1084, type: !1556, isLocal: false, isDefinition: false, scopeLine: 1084, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1556 = !DISubroutineType(types: !1557)
+!1557 = !{!1518, !1532, !1558}
+!1558 = !DIDerivedType(tag: DW_TAG_typedef, name: "difference_type", scope: !1518, file: !879, line: 1019, baseType: !1502)
+!1559 = !DISubprogram(name: "operator+=", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEpLEl", scope: !1518, file: !879, line: 1088, type: !1560, isLocal: false, isDefinition: false, scopeLine: 1088, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1560 = !DISubroutineType(types: !1561)
+!1561 = !{!1549, !1524, !1558}
+!1562 = !DISubprogram(name: "operator-", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEEmiEl", scope: !1518, file: !879, line: 1095, type: !1556, isLocal: false, isDefinition: false, scopeLine: 1095, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1563 = !DISubprogram(name: "operator-=", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEmIEl", scope: !1518, file: !879, line: 1099, type: !1560, isLocal: false, isDefinition: false, scopeLine: 1099, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1564 = !DISubprogram(name: "operator[]", linkageName: "_ZNKSt13move_iteratorIPSt4pairIiiEEixEl", scope: !1518, file: !879, line: 1106, type: !1565, isLocal: false, isDefinition: false, scopeLine: 1106, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1565 = !DISubroutineType(types: !1566)
+!1566 = !{!1537, !1532, !1558}
+!1567 = !{!1568}
+!1568 = !DIGlobalVariableExpression(var: !1569, expr: !DIExpression())
+!1569 = distinct !DIGlobalVariable(name: "gLsbReleasePath", linkageName: "_ZN7mozilla6widget3lsbL15gLsbReleasePathE", scope: !1570, file: !1, line: 17, type: !1443, isLocal: true, isDefinition: true)
+!1570 = !DINamespace(name: "lsb", scope: !1571)
+!1571 = !DINamespace(name: "widget", scope: !20)
+!1572 = !{!1573, !1578, !1630, !1634, !1640, !1644, !1650, !1654, !1659, !1661, !1666, !1670, !1674, !1684, !1688, !1692, !1696, !1700, !1704, !1708, !1712, !1716, !1720, !1729, !1733, !1737, !1739, !1743, !1747, !1751, !1757, !1761, !1765, !1767, !1775, !1779, !1786, !1788, !1792, !1796, !1800, !1804, !1809, !1814, !1819, !1820, !1821, !1822, !1824, !1825, !1826, !1827, !1828, !1829, !1830, !1832, !1833, !1834, !1835, !1836, !1837, !1838, !1843, !1844, !1845, !1846, !1847, !1848, !1849, !1850, !1851, !1852, !1853, !1854, !1855, !1856, !1857, !1858, !1859, !1860, !1861, !1862, !1863, !1864, !1865, !1866, !1867, !1873, !1877, !1884, !1888, !1892, !1896, !1900, !1902, !1904, !1908, !1912, !1916, !1920, !1924, !1926, !1928, !1930, !1934, !1938, !1942, !1944, !1946, !1950, !1967, !1970, !1975, !1984, !1990, !1994, !1998, !2002, !2006, !2008, !2010, !2014, !2020, !2024, !2030, !2036, !2038, !2042, !2046, !2050, !2054, !2065, !2067, !2071, !2075, !2079, !2081, !2085, !2089, !2093, !2095, !2097, !2101, !2109, !2113, !2117, !2121, !2123, !2129, !2131, !2137, !2141, !2145, !2149, !2153, !2157, !2161, !2163, !2165, !2169, !2173, !2177, !2179, !2183, !2187, !2189, !2191, !2195, !2199, !2203, !2207, !2208, !2209, !2210, !2211, !2212, !2213, !2214, !2215, !2216, !2217, !2223, !2227, !2230, !2233, !2236, !2238, !2240, !2242, !2245, !2248, !2251, !2254, !2257, !2259, !2262, !2266, !2267, !2270, !2272, !2274, !2276, !2278, !2281, !2284, !2287, !2290, !2293, !2295, !2296, !2297, !2301, !2305, !2310, !2314, !2316, !2318, !2320, !2322, !2324, !2326, !2328, !2330, !2332, !2334, !2336, !2338, !2340, !2344, !2350, !2355, !2359, !2361, !2363, !2365, !2367, !2374, !2379, !2383, !2387, !2391, !2395, !2399, !2403, !2405, !2409, !2415, !2419, !2423, !2425, !2427, !2431, !2435, !2437, !2439, !2441, !2443, !2445, !2447, !2449, !2453, !2457, !2461, !2465, !2469, !2473, !2475, !2479, !2483, !2487, !2491, !2493, !2495, !2499, !2503, !2504, !2505, !2506, !2507, !2508, !2514, !2517, !2518, !2520, !2522, !2524, !2526, !2530, !2532, !2534, !2536, !2538, !2540, !2542, !2544, !2546, !2550, !2554, !2556, !2560, !2564, !2566, !2569, !2575, !2577, !2579, !2583, !2585, !2587, !2589, !2591, !2593, !2595, !2597, !2602, !2606, !2608, !2610, !2615, !2617, !2619, !2621, !2623, !2625, !2627, !2630, !2632, !2634, !2638, !2642, !2644, !2646, !2648, !2650, !2652, !2654, !2656, !2658, !2660, !2662, !2666, !2670, !2672, !2674, !2676, !2678, !2680, !2682, !2684, !2686, !2688, !2690, !2692, !2694, !2696, !2698, !2700, !2704, !2708, !2712, !2714, !2716, !2718, !2720, !2722, !2724, !2726, !2728, !2730, !2734, !2738, !2742, !2744, !2746, !2748, !2752, !2756, !2760, !2762, !2764, !2766, !2768, !2770, !2772, !2774, !2776, !2778, !2780, !2782, !2784, !2788, !2792, !2796, !2798, !2800, !2802, !2804, !2808, !2812, !2814, !2816, !2818, !2820, !2822, !2824, !2828, !2832, !2834, !2836, !2838, !2840, !2844, !2848, !2852, !2854, !2856, !2858, !2860, !2862, !2864, !2868, !2872, !2876, !2878, !2882, !2886, !2888, !2890, !2892, !2894, !2896, !2898}
+!1573 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1574, file: !1577, line: 56)
+!1574 = !DIDerivedType(tag: DW_TAG_typedef, name: "max_align_t", file: !1575, line: 40, baseType: !1576)
+!1575 = !DIFile(filename: "/usr/lib/clang/7.0.0/include/__stddef_max_align_t.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1576 = !DICompositeType(tag: DW_TAG_structure_type, file: !1575, line: 35, flags: DIFlagFwdDecl, identifier: "_ZTS11max_align_t")
+!1577 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cstddef", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1578 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1579, file: !1580, line: 57)
+!1579 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "exception_ptr", scope: !1581, file: !1580, line: 79, size: 64, flags: DIFlagTypePassByReference, elements: !1582, identifier: "_ZTSNSt15__exception_ptr13exception_ptrE")
+!1580 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/exception_ptr.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1581 = !DINamespace(name: "__exception_ptr", scope: !13)
+!1582 = !{!1583, !1584, !1588, !1591, !1592, !1597, !1598, !1602, !1605, !1609, !1613, !1616, !1617, !1620, !1623}
+!1583 = !DIDerivedType(tag: DW_TAG_member, name: "_M_exception_object", scope: !1579, file: !1580, line: 81, baseType: !506, size: 64)
+!1584 = !DISubprogram(name: "exception_ptr", scope: !1579, file: !1580, line: 83, type: !1585, isLocal: false, isDefinition: false, scopeLine: 83, flags: DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1585 = !DISubroutineType(types: !1586)
+!1586 = !{null, !1587, !506}
+!1587 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1579, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1588 = !DISubprogram(name: "_M_addref", linkageName: "_ZNSt15__exception_ptr13exception_ptr9_M_addrefEv", scope: !1579, file: !1580, line: 85, type: !1589, isLocal: false, isDefinition: false, scopeLine: 85, flags: DIFlagPrototyped, isOptimized: true)
+!1589 = !DISubroutineType(types: !1590)
+!1590 = !{null, !1587}
+!1591 = !DISubprogram(name: "_M_release", linkageName: "_ZNSt15__exception_ptr13exception_ptr10_M_releaseEv", scope: !1579, file: !1580, line: 86, type: !1589, isLocal: false, isDefinition: false, scopeLine: 86, flags: DIFlagPrototyped, isOptimized: true)
+!1592 = !DISubprogram(name: "_M_get", linkageName: "_ZNKSt15__exception_ptr13exception_ptr6_M_getEv", scope: !1579, file: !1580, line: 88, type: !1593, isLocal: false, isDefinition: false, scopeLine: 88, flags: DIFlagPrototyped, isOptimized: true)
+!1593 = !DISubroutineType(types: !1594)
+!1594 = !{!506, !1595}
+!1595 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1596, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!1596 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1579)
+!1597 = !DISubprogram(name: "exception_ptr", scope: !1579, file: !1580, line: 96, type: !1589, isLocal: false, isDefinition: false, scopeLine: 96, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1598 = !DISubprogram(name: "exception_ptr", scope: !1579, file: !1580, line: 98, type: !1599, isLocal: false, isDefinition: false, scopeLine: 98, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1599 = !DISubroutineType(types: !1600)
+!1600 = !{null, !1587, !1601}
+!1601 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1596, size: 64)
+!1602 = !DISubprogram(name: "exception_ptr", scope: !1579, file: !1580, line: 101, type: !1603, isLocal: false, isDefinition: false, scopeLine: 101, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1603 = !DISubroutineType(types: !1604)
+!1604 = !{null, !1587, !501}
+!1605 = !DISubprogram(name: "exception_ptr", scope: !1579, file: !1580, line: 105, type: !1606, isLocal: false, isDefinition: false, scopeLine: 105, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1606 = !DISubroutineType(types: !1607)
+!1607 = !{null, !1587, !1608}
+!1608 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !1579, size: 64)
+!1609 = !DISubprogram(name: "operator=", linkageName: "_ZNSt15__exception_ptr13exception_ptraSERKS0_", scope: !1579, file: !1580, line: 118, type: !1610, isLocal: false, isDefinition: false, scopeLine: 118, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1610 = !DISubroutineType(types: !1611)
+!1611 = !{!1612, !1587, !1601}
+!1612 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1579, size: 64)
+!1613 = !DISubprogram(name: "operator=", linkageName: "_ZNSt15__exception_ptr13exception_ptraSEOS0_", scope: !1579, file: !1580, line: 122, type: !1614, isLocal: false, isDefinition: false, scopeLine: 122, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1614 = !DISubroutineType(types: !1615)
+!1615 = !{!1612, !1587, !1608}
+!1616 = !DISubprogram(name: "~exception_ptr", scope: !1579, file: !1580, line: 129, type: !1589, isLocal: false, isDefinition: false, scopeLine: 129, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1617 = !DISubprogram(name: "swap", linkageName: "_ZNSt15__exception_ptr13exception_ptr4swapERS0_", scope: !1579, file: !1580, line: 132, type: !1618, isLocal: false, isDefinition: false, scopeLine: 132, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1618 = !DISubroutineType(types: !1619)
+!1619 = !{null, !1587, !1612}
+!1620 = !DISubprogram(name: "operator bool", linkageName: "_ZNKSt15__exception_ptr13exception_ptrcvbEv", scope: !1579, file: !1580, line: 144, type: !1621, isLocal: false, isDefinition: false, scopeLine: 144, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!1621 = !DISubroutineType(types: !1622)
+!1622 = !{!117, !1595}
+!1623 = !DISubprogram(name: "__cxa_exception_type", linkageName: "_ZNKSt15__exception_ptr13exception_ptr20__cxa_exception_typeEv", scope: !1579, file: !1580, line: 153, type: !1624, isLocal: false, isDefinition: false, scopeLine: 153, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!1624 = !DISubroutineType(types: !1625)
+!1625 = !{!1626, !1595}
+!1626 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1627, size: 64)
+!1627 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1628)
+!1628 = !DICompositeType(tag: DW_TAG_class_type, name: "type_info", scope: !13, file: !1629, line: 88, flags: DIFlagFwdDecl, identifier: "_ZTSSt9type_info")
+!1629 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/typeinfo", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1630 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !1581, entity: !1631, file: !1580, line: 73)
+!1631 = !DISubprogram(name: "rethrow_exception", linkageName: "_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE", scope: !13, file: !1580, line: 69, type: !1632, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true)
+!1632 = !DISubroutineType(types: !1633)
+!1633 = !{null, !1579}
+!1634 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1635, file: !1639, line: 52)
+!1635 = !DISubprogram(name: "abs", scope: !1636, file: !1636, line: 837, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1636 = !DIFile(filename: "/usr/include/stdlib.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1637 = !DISubroutineType(types: !1638)
+!1638 = !{!93, !93}
+!1639 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/std_abs.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1640 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1641, file: !1643, line: 127)
+!1641 = !DIDerivedType(tag: DW_TAG_typedef, name: "div_t", file: !1636, line: 62, baseType: !1642)
+!1642 = !DICompositeType(tag: DW_TAG_structure_type, file: !1636, line: 58, flags: DIFlagFwdDecl, identifier: "_ZTS5div_t")
+!1643 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cstdlib", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1644 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1645, file: !1643, line: 128)
+!1645 = !DIDerivedType(tag: DW_TAG_typedef, name: "ldiv_t", file: !1636, line: 70, baseType: !1646)
+!1646 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1636, line: 66, size: 128, flags: DIFlagTypePassByValue, elements: !1647, identifier: "_ZTS6ldiv_t")
+!1647 = !{!1648, !1649}
+!1648 = !DIDerivedType(tag: DW_TAG_member, name: "quot", scope: !1646, file: !1636, line: 68, baseType: !1504, size: 64)
+!1649 = !DIDerivedType(tag: DW_TAG_member, name: "rem", scope: !1646, file: !1636, line: 69, baseType: !1504, size: 64, offset: 64)
+!1650 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1651, file: !1643, line: 130)
+!1651 = !DISubprogram(name: "abort", scope: !1636, file: !1636, line: 588, type: !1652, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true)
+!1652 = !DISubroutineType(types: !1653)
+!1653 = !{null}
+!1654 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1655, file: !1643, line: 134)
+!1655 = !DISubprogram(name: "atexit", scope: !1636, file: !1636, line: 592, type: !1656, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1656 = !DISubroutineType(types: !1657)
+!1657 = !{!93, !1658}
+!1658 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1652, size: 64)
+!1659 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1660, file: !1643, line: 137)
+!1660 = !DISubprogram(name: "at_quick_exit", scope: !1636, file: !1636, line: 597, type: !1656, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1661 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1662, file: !1643, line: 140)
+!1662 = !DISubprogram(name: "atof", scope: !1636, file: !1636, line: 101, type: !1663, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1663 = !DISubroutineType(types: !1664)
+!1664 = !{!1665, !1443}
+!1665 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
+!1666 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1667, file: !1643, line: 141)
+!1667 = !DISubprogram(name: "atoi", scope: !1636, file: !1636, line: 104, type: !1668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1668 = !DISubroutineType(types: !1669)
+!1669 = !{!93, !1443}
+!1670 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1671, file: !1643, line: 142)
+!1671 = !DISubprogram(name: "atol", scope: !1636, file: !1636, line: 107, type: !1672, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1672 = !DISubroutineType(types: !1673)
+!1673 = !{!1504, !1443}
+!1674 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1675, file: !1643, line: 143)
+!1675 = !DISubprogram(name: "bsearch", scope: !1636, file: !1636, line: 817, type: !1676, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1676 = !DISubroutineType(types: !1677)
+!1677 = !{!506, !178, !178, !1678, !1678, !1680}
+!1678 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_t", file: !1679, line: 62, baseType: !177)
+!1679 = !DIFile(filename: "/usr/lib/clang/7.0.0/include/stddef.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1680 = !DIDerivedType(tag: DW_TAG_typedef, name: "__compar_fn_t", file: !1636, line: 805, baseType: !1681)
+!1681 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1682, size: 64)
+!1682 = !DISubroutineType(types: !1683)
+!1683 = !{!93, !178, !178}
+!1684 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1685, file: !1643, line: 144)
+!1685 = !DISubprogram(name: "calloc", scope: !1636, file: !1636, line: 541, type: !1686, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1686 = !DISubroutineType(types: !1687)
+!1687 = !{!506, !1678, !1678}
+!1688 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1689, file: !1643, line: 145)
+!1689 = !DISubprogram(name: "div", scope: !1636, file: !1636, line: 849, type: !1690, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1690 = !DISubroutineType(types: !1691)
+!1691 = !{!1641, !93, !93}
+!1692 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1693, file: !1643, line: 146)
+!1693 = !DISubprogram(name: "exit", scope: !1636, file: !1636, line: 614, type: !1694, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true)
+!1694 = !DISubroutineType(types: !1695)
+!1695 = !{null, !93}
+!1696 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1697, file: !1643, line: 147)
+!1697 = !DISubprogram(name: "free", scope: !1636, file: !1636, line: 563, type: !1698, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1698 = !DISubroutineType(types: !1699)
+!1699 = !{null, !506}
+!1700 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1701, file: !1643, line: 148)
+!1701 = !DISubprogram(name: "getenv", scope: !1636, file: !1636, line: 631, type: !1702, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1702 = !DISubroutineType(types: !1703)
+!1703 = !{!1170, !1443}
+!1704 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1705, file: !1643, line: 149)
+!1705 = !DISubprogram(name: "labs", scope: !1636, file: !1636, line: 838, type: !1706, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1706 = !DISubroutineType(types: !1707)
+!1707 = !{!1504, !1504}
+!1708 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1709, file: !1643, line: 150)
+!1709 = !DISubprogram(name: "ldiv", scope: !1636, file: !1636, line: 851, type: !1710, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1710 = !DISubroutineType(types: !1711)
+!1711 = !{!1645, !1504, !1504}
+!1712 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1713, file: !1643, line: 151)
+!1713 = !DISubprogram(name: "malloc", scope: !1636, file: !1636, line: 539, type: !1714, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1714 = !DISubroutineType(types: !1715)
+!1715 = !{!506, !1678}
+!1716 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1717, file: !1643, line: 153)
+!1717 = !DISubprogram(name: "mblen", scope: !1636, file: !1636, line: 919, type: !1718, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1718 = !DISubroutineType(types: !1719)
+!1719 = !{!93, !1443, !1678}
+!1720 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1721, file: !1643, line: 154)
+!1721 = !DISubprogram(name: "mbstowcs", scope: !1722, file: !1722, line: 113, type: !1723, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1722 = !DIFile(filename: "/usr/include/bits/stdlib.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1723 = !DISubroutineType(types: !1724)
+!1724 = !{!1678, !1725, !1728, !1678}
+!1725 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1726)
+!1726 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1727, size: 64)
+!1727 = !DIBasicType(name: "wchar_t", size: 32, encoding: DW_ATE_signed)
+!1728 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1443)
+!1729 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1730, file: !1643, line: 155)
+!1730 = !DISubprogram(name: "mbtowc", scope: !1636, file: !1636, line: 922, type: !1731, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1731 = !DISubroutineType(types: !1732)
+!1732 = !{!93, !1725, !1728, !1678}
+!1733 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1734, file: !1643, line: 157)
+!1734 = !DISubprogram(name: "qsort", scope: !1636, file: !1636, line: 827, type: !1735, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1735 = !DISubroutineType(types: !1736)
+!1736 = !{null, !506, !1678, !1678, !1680}
+!1737 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1738, file: !1643, line: 160)
+!1738 = !DISubprogram(name: "quick_exit", scope: !1636, file: !1636, line: 620, type: !1694, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true)
+!1739 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1740, file: !1643, line: 163)
+!1740 = !DISubprogram(name: "rand", scope: !1636, file: !1636, line: 453, type: !1741, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1741 = !DISubroutineType(types: !1742)
+!1742 = !{!93}
+!1743 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1744, file: !1643, line: 164)
+!1744 = !DISubprogram(name: "realloc", scope: !1636, file: !1636, line: 549, type: !1745, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1745 = !DISubroutineType(types: !1746)
+!1746 = !{!506, !506, !1678}
+!1747 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1748, file: !1643, line: 165)
+!1748 = !DISubprogram(name: "srand", scope: !1636, file: !1636, line: 455, type: !1749, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1749 = !DISubroutineType(types: !1750)
+!1750 = !{null, !6}
+!1751 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1752, file: !1643, line: 166)
+!1752 = !DISubprogram(name: "strtod", scope: !1636, file: !1636, line: 117, type: !1753, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1753 = !DISubroutineType(types: !1754)
+!1754 = !{!1665, !1728, !1755}
+!1755 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1756)
+!1756 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1170, size: 64)
+!1757 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1758, file: !1643, line: 167)
+!1758 = !DISubprogram(name: "strtol", scope: !1636, file: !1636, line: 176, type: !1759, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1759 = !DISubroutineType(types: !1760)
+!1760 = !{!1504, !1728, !1755, !93}
+!1761 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1762, file: !1643, line: 168)
+!1762 = !DISubprogram(name: "strtoul", scope: !1636, file: !1636, line: 180, type: !1763, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1763 = !DISubroutineType(types: !1764)
+!1764 = !{!177, !1728, !1755, !93}
+!1765 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1766, file: !1643, line: 169)
+!1766 = !DISubprogram(name: "system", scope: !1636, file: !1636, line: 781, type: !1668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1767 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1768, file: !1643, line: 171)
+!1768 = !DISubprogram(name: "wcstombs", scope: !1722, file: !1722, line: 144, type: !1769, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1769 = !DISubroutineType(types: !1770)
+!1770 = !{!1678, !1771, !1772, !1678}
+!1771 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1170)
+!1772 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1773)
+!1773 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1774, size: 64)
+!1774 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1727)
+!1775 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1776, file: !1643, line: 172)
+!1776 = !DISubprogram(name: "wctomb", scope: !1722, file: !1722, line: 83, type: !1777, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1777 = !DISubroutineType(types: !1778)
+!1778 = !{!93, !1170, !1727}
+!1779 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1780, file: !1643, line: 200)
+!1780 = !DIDerivedType(tag: DW_TAG_typedef, name: "lldiv_t", file: !1636, line: 80, baseType: !1781)
+!1781 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1636, line: 76, size: 128, flags: DIFlagTypePassByValue, elements: !1782, identifier: "_ZTS7lldiv_t")
+!1782 = !{!1783, !1785}
+!1783 = !DIDerivedType(tag: DW_TAG_member, name: "quot", scope: !1781, file: !1636, line: 78, baseType: !1784, size: 64)
+!1784 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed)
+!1785 = !DIDerivedType(tag: DW_TAG_member, name: "rem", scope: !1781, file: !1636, line: 79, baseType: !1784, size: 64, offset: 64)
+!1786 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1787, file: !1643, line: 206)
+!1787 = !DISubprogram(name: "_Exit", scope: !1636, file: !1636, line: 626, type: !1694, isLocal: false, isDefinition: false, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true)
+!1788 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1789, file: !1643, line: 210)
+!1789 = !DISubprogram(name: "llabs", scope: !1636, file: !1636, line: 841, type: !1790, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1790 = !DISubroutineType(types: !1791)
+!1791 = !{!1784, !1784}
+!1792 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1793, file: !1643, line: 216)
+!1793 = !DISubprogram(name: "lldiv", scope: !1636, file: !1636, line: 855, type: !1794, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1794 = !DISubroutineType(types: !1795)
+!1795 = !{!1780, !1784, !1784}
+!1796 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1797, file: !1643, line: 227)
+!1797 = !DISubprogram(name: "atoll", scope: !1636, file: !1636, line: 112, type: !1798, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1798 = !DISubroutineType(types: !1799)
+!1799 = !{!1784, !1443}
+!1800 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1801, file: !1643, line: 228)
+!1801 = !DISubprogram(name: "strtoll", scope: !1636, file: !1636, line: 200, type: !1802, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1802 = !DISubroutineType(types: !1803)
+!1803 = !{!1784, !1728, !1755, !93}
+!1804 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1805, file: !1643, line: 229)
+!1805 = !DISubprogram(name: "strtoull", scope: !1636, file: !1636, line: 205, type: !1806, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1806 = !DISubroutineType(types: !1807)
+!1807 = !{!1808, !1728, !1755, !93}
+!1808 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned)
+!1809 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1810, file: !1643, line: 231)
+!1810 = !DISubprogram(name: "strtof", scope: !1636, file: !1636, line: 123, type: !1811, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1811 = !DISubroutineType(types: !1812)
+!1812 = !{!1813, !1728, !1755}
+!1813 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!1814 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1815, file: !1643, line: 232)
+!1815 = !DISubprogram(name: "strtold", scope: !1636, file: !1636, line: 126, type: !1816, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1816 = !DISubroutineType(types: !1817)
+!1817 = !{!1818, !1728, !1755}
+!1818 = !DIBasicType(name: "long double", size: 128, encoding: DW_ATE_float)
+!1819 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1780, file: !1643, line: 240)
+!1820 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1787, file: !1643, line: 242)
+!1821 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1789, file: !1643, line: 244)
+!1822 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1823, file: !1643, line: 245)
+!1823 = !DISubprogram(name: "div", linkageName: "_ZN9__gnu_cxx3divExx", scope: !5, file: !1643, line: 213, type: !1794, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1824 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1793, file: !1643, line: 246)
+!1825 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1797, file: !1643, line: 248)
+!1826 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1810, file: !1643, line: 249)
+!1827 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1801, file: !1643, line: 250)
+!1828 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1805, file: !1643, line: 251)
+!1829 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1815, file: !1643, line: 252)
+!1830 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1651, file: !1831, line: 38)
+!1831 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/stdlib.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1832 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1655, file: !1831, line: 39)
+!1833 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1693, file: !1831, line: 40)
+!1834 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1660, file: !1831, line: 43)
+!1835 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1738, file: !1831, line: 46)
+!1836 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1641, file: !1831, line: 51)
+!1837 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1645, file: !1831, line: 52)
+!1838 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1839, file: !1831, line: 54)
+!1839 = !DISubprogram(name: "abs", linkageName: "_ZSt3absg", scope: !13, file: !1639, line: 102, type: !1840, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1840 = !DISubroutineType(types: !1841)
+!1841 = !{!1842, !1842}
+!1842 = !DIBasicType(name: "__float128", size: 128, encoding: DW_ATE_float)
+!1843 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1662, file: !1831, line: 55)
+!1844 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1667, file: !1831, line: 56)
+!1845 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1671, file: !1831, line: 57)
+!1846 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1675, file: !1831, line: 58)
+!1847 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1685, file: !1831, line: 59)
+!1848 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1823, file: !1831, line: 60)
+!1849 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1697, file: !1831, line: 61)
+!1850 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1701, file: !1831, line: 62)
+!1851 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1705, file: !1831, line: 63)
+!1852 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1709, file: !1831, line: 64)
+!1853 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1713, file: !1831, line: 65)
+!1854 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1717, file: !1831, line: 67)
+!1855 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1721, file: !1831, line: 68)
+!1856 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1730, file: !1831, line: 69)
+!1857 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1734, file: !1831, line: 71)
+!1858 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1740, file: !1831, line: 72)
+!1859 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1744, file: !1831, line: 73)
+!1860 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1748, file: !1831, line: 74)
+!1861 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1752, file: !1831, line: 75)
+!1862 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1758, file: !1831, line: 76)
+!1863 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1762, file: !1831, line: 77)
+!1864 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1766, file: !1831, line: 78)
+!1865 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1768, file: !1831, line: 80)
+!1866 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !1776, file: !1831, line: 81)
+!1867 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1868, file: !1872, line: 75)
+!1868 = !DISubprogram(name: "memchr", scope: !1869, file: !1869, line: 90, type: !1870, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1869 = !DIFile(filename: "/usr/include/string.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1870 = !DISubroutineType(types: !1871)
+!1871 = !{!506, !178, !93, !1678}
+!1872 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cstring", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1873 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1874, file: !1872, line: 76)
+!1874 = !DISubprogram(name: "memcmp", scope: !1869, file: !1869, line: 63, type: !1875, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1875 = !DISubroutineType(types: !1876)
+!1876 = !{!93, !178, !178, !1678}
+!1877 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1878, file: !1872, line: 77)
+!1878 = !DISubprogram(name: "memcpy", scope: !1879, file: !1879, line: 31, type: !1880, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1879 = !DIFile(filename: "/usr/include/bits/string_fortified.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1880 = !DISubroutineType(types: !1881)
+!1881 = !{!506, !1882, !1883, !1678}
+!1882 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !506)
+!1883 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !178)
+!1884 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1885, file: !1872, line: 78)
+!1885 = !DISubprogram(name: "memmove", scope: !1879, file: !1879, line: 38, type: !1886, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1886 = !DISubroutineType(types: !1887)
+!1887 = !{!506, !506, !178, !1678}
+!1888 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1889, file: !1872, line: 79)
+!1889 = !DISubprogram(name: "memset", scope: !1879, file: !1879, line: 59, type: !1890, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1890 = !DISubroutineType(types: !1891)
+!1891 = !{!506, !506, !93, !1678}
+!1892 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1893, file: !1872, line: 80)
+!1893 = !DISubprogram(name: "strcat", scope: !1879, file: !1879, line: 126, type: !1894, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1894 = !DISubroutineType(types: !1895)
+!1895 = !{!1170, !1771, !1728}
+!1896 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1897, file: !1872, line: 81)
+!1897 = !DISubprogram(name: "strcmp", scope: !1869, file: !1869, line: 136, type: !1898, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1898 = !DISubroutineType(types: !1899)
+!1899 = !{!93, !1443, !1443}
+!1900 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1901, file: !1872, line: 82)
+!1901 = !DISubprogram(name: "strcoll", scope: !1869, file: !1869, line: 143, type: !1898, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1902 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1903, file: !1872, line: 83)
+!1903 = !DISubprogram(name: "strcpy", scope: !1879, file: !1879, line: 88, type: !1894, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1904 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1905, file: !1872, line: 84)
+!1905 = !DISubprogram(name: "strcspn", scope: !1869, file: !1869, line: 272, type: !1906, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1906 = !DISubroutineType(types: !1907)
+!1907 = !{!1678, !1443, !1443}
+!1908 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1909, file: !1872, line: 85)
+!1909 = !DISubprogram(name: "strerror", scope: !1869, file: !1869, line: 396, type: !1910, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1910 = !DISubroutineType(types: !1911)
+!1911 = !{!1170, !93}
+!1912 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1913, file: !1872, line: 86)
+!1913 = !DISubprogram(name: "strlen", scope: !1869, file: !1869, line: 384, type: !1914, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1914 = !DISubroutineType(types: !1915)
+!1915 = !{!1678, !1443}
+!1916 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1917, file: !1872, line: 87)
+!1917 = !DISubprogram(name: "strncat", scope: !1879, file: !1879, line: 133, type: !1918, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1918 = !DISubroutineType(types: !1919)
+!1919 = !{!1170, !1771, !1728, !1678}
+!1920 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1921, file: !1872, line: 88)
+!1921 = !DISubprogram(name: "strncmp", scope: !1869, file: !1869, line: 139, type: !1922, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1922 = !DISubroutineType(types: !1923)
+!1923 = !{!93, !1443, !1443, !1678}
+!1924 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1925, file: !1872, line: 89)
+!1925 = !DISubprogram(name: "strncpy", scope: !1879, file: !1879, line: 103, type: !1918, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1926 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1927, file: !1872, line: 90)
+!1927 = !DISubprogram(name: "strspn", scope: !1869, file: !1869, line: 276, type: !1906, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1928 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1929, file: !1872, line: 91)
+!1929 = !DISubprogram(name: "strtok", scope: !1869, file: !1869, line: 335, type: !1894, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1930 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1931, file: !1872, line: 92)
+!1931 = !DISubprogram(name: "strxfrm", scope: !1869, file: !1869, line: 146, type: !1932, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1932 = !DISubroutineType(types: !1933)
+!1933 = !{!1678, !1771, !1728, !1678}
+!1934 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1935, file: !1872, line: 93)
+!1935 = !DISubprogram(name: "strchr", scope: !1869, file: !1869, line: 225, type: !1936, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1936 = !DISubroutineType(types: !1937)
+!1937 = !{!1170, !1443, !93}
+!1938 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1939, file: !1872, line: 94)
+!1939 = !DISubprogram(name: "strpbrk", scope: !1869, file: !1869, line: 302, type: !1940, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1940 = !DISubroutineType(types: !1941)
+!1941 = !{!1170, !1443, !1443}
+!1942 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1943, file: !1872, line: 95)
+!1943 = !DISubprogram(name: "strrchr", scope: !1869, file: !1869, line: 252, type: !1936, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1944 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1945, file: !1872, line: 96)
+!1945 = !DISubprogram(name: "strstr", scope: !1869, file: !1869, line: 329, type: !1940, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1946 = !DIImportedEntity(tag: DW_TAG_imported_module, scope: !1947, entity: !1948, file: !1949, line: 58)
+!1947 = !DINamespace(name: "__gnu_debug", scope: null)
+!1948 = !DINamespace(name: "__debug", scope: !13)
+!1949 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/debug/debug.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1950 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1951, file: !1966, line: 64)
+!1951 = !DIDerivedType(tag: DW_TAG_typedef, name: "mbstate_t", file: !1952, line: 6, baseType: !1953)
+!1952 = !DIFile(filename: "/usr/include/bits/types/mbstate_t.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1953 = !DIDerivedType(tag: DW_TAG_typedef, name: "__mbstate_t", file: !1954, line: 21, baseType: !1955)
+!1954 = !DIFile(filename: "/usr/include/bits/types/__mbstate_t.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1955 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1954, line: 13, size: 64, flags: DIFlagTypePassByValue, elements: !1956, identifier: "_ZTS11__mbstate_t")
+!1956 = !{!1957, !1958}
+!1957 = !DIDerivedType(tag: DW_TAG_member, name: "__count", scope: !1955, file: !1954, line: 15, baseType: !93, size: 32)
+!1958 = !DIDerivedType(tag: DW_TAG_member, name: "__value", scope: !1955, file: !1954, line: 20, baseType: !1959, size: 32, offset: 32)
+!1959 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !1955, file: !1954, line: 16, size: 32, flags: DIFlagTypePassByValue, elements: !1960, identifier: "_ZTSN11__mbstate_tUt_E")
+!1960 = !{!1961, !1962}
+!1961 = !DIDerivedType(tag: DW_TAG_member, name: "__wch", scope: !1959, file: !1954, line: 18, baseType: !6, size: 32)
+!1962 = !DIDerivedType(tag: DW_TAG_member, name: "__wchb", scope: !1959, file: !1954, line: 19, baseType: !1963, size: 32)
+!1963 = !DICompositeType(tag: DW_TAG_array_type, baseType: !1171, size: 32, elements: !1964)
+!1964 = !{!1965}
+!1965 = !DISubrange(count: 4)
+!1966 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cwchar", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1967 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1968, file: !1966, line: 139)
+!1968 = !DIDerivedType(tag: DW_TAG_typedef, name: "wint_t", file: !1969, line: 20, baseType: !6)
+!1969 = !DIFile(filename: "/usr/include/bits/types/wint_t.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1970 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1971, file: !1966, line: 141)
+!1971 = !DISubprogram(name: "btowc", scope: !1972, file: !1972, line: 284, type: !1973, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1972 = !DIFile(filename: "/usr/include/wchar.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1973 = !DISubroutineType(types: !1974)
+!1974 = !{!1968, !93}
+!1975 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1976, file: !1966, line: 142)
+!1976 = !DISubprogram(name: "fgetwc", scope: !1972, file: !1972, line: 727, type: !1977, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1977 = !DISubroutineType(types: !1978)
+!1978 = !{!1968, !1979}
+!1979 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1980, size: 64)
+!1980 = !DIDerivedType(tag: DW_TAG_typedef, name: "__FILE", file: !1981, line: 5, baseType: !1982)
+!1981 = !DIFile(filename: "/usr/include/bits/types/__FILE.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1982 = !DICompositeType(tag: DW_TAG_structure_type, name: "_IO_FILE", file: !1983, line: 49, flags: DIFlagFwdDecl, identifier: "_ZTS8_IO_FILE")
+!1983 = !DIFile(filename: "/usr/include/bits/types/struct_FILE.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1984 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1985, file: !1966, line: 143)
+!1985 = !DISubprogram(name: "fgetws", scope: !1986, file: !1986, line: 384, type: !1987, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1986 = !DIFile(filename: "/usr/include/bits/wchar2.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!1987 = !DISubroutineType(types: !1988)
+!1988 = !{!1726, !1725, !93, !1989}
+!1989 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !1979)
+!1990 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1991, file: !1966, line: 144)
+!1991 = !DISubprogram(name: "fputwc", scope: !1972, file: !1972, line: 741, type: !1992, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1992 = !DISubroutineType(types: !1993)
+!1993 = !{!1968, !1727, !1979}
+!1994 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1995, file: !1966, line: 145)
+!1995 = !DISubprogram(name: "fputws", scope: !1972, file: !1972, line: 763, type: !1996, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!1996 = !DISubroutineType(types: !1997)
+!1997 = !{!93, !1772, !1989}
+!1998 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1999, file: !1966, line: 146)
+!1999 = !DISubprogram(name: "fwide", scope: !1972, file: !1972, line: 573, type: !2000, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2000 = !DISubroutineType(types: !2001)
+!2001 = !{!93, !1979, !93}
+!2002 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2003, file: !1966, line: 147)
+!2003 = !DISubprogram(name: "fwprintf", scope: !1972, file: !1972, line: 580, type: !2004, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2004 = !DISubroutineType(types: !2005)
+!2005 = !{!93, !1989, !1772, null}
+!2006 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2007, file: !1966, line: 148)
+!2007 = !DISubprogram(name: "fwscanf", scope: !1972, file: !1972, line: 621, type: !2004, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2008 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2009, file: !1966, line: 149)
+!2009 = !DISubprogram(name: "getwc", scope: !1972, file: !1972, line: 728, type: !1977, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2010 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2011, file: !1966, line: 150)
+!2011 = !DISubprogram(name: "getwchar", scope: !1972, file: !1972, line: 734, type: !2012, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2012 = !DISubroutineType(types: !2013)
+!2013 = !{!1968}
+!2014 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2015, file: !1966, line: 151)
+!2015 = !DISubprogram(name: "mbrlen", scope: !1972, file: !1972, line: 307, type: !2016, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2016 = !DISubroutineType(types: !2017)
+!2017 = !{!1678, !1728, !1678, !2018}
+!2018 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2019)
+!2019 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1951, size: 64)
+!2020 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2021, file: !1966, line: 152)
+!2021 = !DISubprogram(name: "mbrtowc", scope: !1972, file: !1972, line: 296, type: !2022, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2022 = !DISubroutineType(types: !2023)
+!2023 = !{!1678, !1725, !1728, !1678, !2018}
+!2024 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2025, file: !1966, line: 153)
+!2025 = !DISubprogram(name: "mbsinit", scope: !1972, file: !1972, line: 292, type: !2026, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2026 = !DISubroutineType(types: !2027)
+!2027 = !{!93, !2028}
+!2028 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2029, size: 64)
+!2029 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1951)
+!2030 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2031, file: !1966, line: 154)
+!2031 = !DISubprogram(name: "mbsrtowcs", scope: !1986, file: !1986, line: 474, type: !2032, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2032 = !DISubroutineType(types: !2033)
+!2033 = !{!1678, !1725, !2034, !1678, !2018}
+!2034 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2035)
+!2035 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1443, size: 64)
+!2036 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2037, file: !1966, line: 155)
+!2037 = !DISubprogram(name: "putwc", scope: !1972, file: !1972, line: 742, type: !1992, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2038 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2039, file: !1966, line: 156)
+!2039 = !DISubprogram(name: "putwchar", scope: !1972, file: !1972, line: 748, type: !2040, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2040 = !DISubroutineType(types: !2041)
+!2041 = !{!1968, !1727}
+!2042 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2043, file: !1966, line: 158)
+!2043 = !DISubprogram(name: "swprintf", scope: !1972, file: !1972, line: 590, type: !2044, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2044 = !DISubroutineType(types: !2045)
+!2045 = !{!93, !1725, !1678, !1772, null}
+!2046 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2047, file: !1966, line: 160)
+!2047 = !DISubprogram(name: "swscanf", scope: !1972, file: !1972, line: 631, type: !2048, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2048 = !DISubroutineType(types: !2049)
+!2049 = !{!93, !1772, !1772, null}
+!2050 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2051, file: !1966, line: 161)
+!2051 = !DISubprogram(name: "ungetwc", scope: !1972, file: !1972, line: 771, type: !2052, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2052 = !DISubroutineType(types: !2053)
+!2053 = !{!1968, !1968, !1979}
+!2054 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2055, file: !1966, line: 162)
+!2055 = !DISubprogram(name: "vfwprintf", scope: !1986, file: !1986, line: 364, type: !2056, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2056 = !DISubroutineType(types: !2057)
+!2057 = !{!93, !1989, !1772, !2058}
+!2058 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2059, size: 64)
+!2059 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag", file: !1, size: 192, flags: DIFlagTypePassByValue, elements: !2060, identifier: "_ZTS13__va_list_tag")
+!2060 = !{!2061, !2062, !2063, !2064}
+!2061 = !DIDerivedType(tag: DW_TAG_member, name: "gp_offset", scope: !2059, file: !1, baseType: !6, size: 32)
+!2062 = !DIDerivedType(tag: DW_TAG_member, name: "fp_offset", scope: !2059, file: !1, baseType: !6, size: 32, offset: 32)
+!2063 = !DIDerivedType(tag: DW_TAG_member, name: "overflow_arg_area", scope: !2059, file: !1, baseType: !506, size: 64, offset: 64)
+!2064 = !DIDerivedType(tag: DW_TAG_member, name: "reg_save_area", scope: !2059, file: !1, baseType: !506, size: 64, offset: 128)
+!2065 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2066, file: !1966, line: 164)
+!2066 = !DISubprogram(name: "vfwscanf", scope: !1972, file: !1972, line: 673, type: !2056, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2067 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2068, file: !1966, line: 167)
+!2068 = !DISubprogram(name: "vswprintf", scope: !1986, file: !1986, line: 315, type: !2069, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2069 = !DISubroutineType(types: !2070)
+!2070 = !{!93, !1725, !1678, !1772, !2058}
+!2071 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2072, file: !1966, line: 170)
+!2072 = !DISubprogram(name: "vswscanf", scope: !1972, file: !1972, line: 685, type: !2073, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2073 = !DISubroutineType(types: !2074)
+!2074 = !{!93, !1772, !1772, !2058}
+!2075 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2076, file: !1966, line: 172)
+!2076 = !DISubprogram(name: "vwprintf", scope: !1986, file: !1986, line: 358, type: !2077, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2077 = !DISubroutineType(types: !2078)
+!2078 = !{!93, !1772, !2058}
+!2079 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2080, file: !1966, line: 174)
+!2080 = !DISubprogram(name: "vwscanf", scope: !1972, file: !1972, line: 681, type: !2077, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2081 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2082, file: !1966, line: 176)
+!2082 = !DISubprogram(name: "wcrtomb", scope: !1986, file: !1986, line: 440, type: !2083, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2083 = !DISubroutineType(types: !2084)
+!2084 = !{!1678, !1771, !1727, !2018}
+!2085 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2086, file: !1966, line: 177)
+!2086 = !DISubprogram(name: "wcscat", scope: !1986, file: !1986, line: 246, type: !2087, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2087 = !DISubroutineType(types: !2088)
+!2088 = !{!1726, !1725, !1772}
+!2089 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2090, file: !1966, line: 178)
+!2090 = !DISubprogram(name: "wcscmp", scope: !1972, file: !1972, line: 106, type: !2091, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2091 = !DISubroutineType(types: !2092)
+!2092 = !{!93, !1773, !1773}
+!2093 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2094, file: !1966, line: 179)
+!2094 = !DISubprogram(name: "wcscoll", scope: !1972, file: !1972, line: 131, type: !2091, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2095 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2096, file: !1966, line: 180)
+!2096 = !DISubprogram(name: "wcscpy", scope: !1986, file: !1986, line: 152, type: !2087, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2097 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2098, file: !1966, line: 181)
+!2098 = !DISubprogram(name: "wcscspn", scope: !1972, file: !1972, line: 187, type: !2099, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2099 = !DISubroutineType(types: !2100)
+!2100 = !{!1678, !1773, !1773}
+!2101 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2102, file: !1966, line: 182)
+!2102 = !DISubprogram(name: "wcsftime", scope: !1972, file: !1972, line: 835, type: !2103, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2103 = !DISubroutineType(types: !2104)
+!2104 = !{!1678, !1725, !1678, !1772, !2105}
+!2105 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2106)
+!2106 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2107, size: 64)
+!2107 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2108)
+!2108 = !DICompositeType(tag: DW_TAG_structure_type, name: "tm", file: !1972, line: 83, flags: DIFlagFwdDecl, identifier: "_ZTS2tm")
+!2109 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2110, file: !1966, line: 183)
+!2110 = !DISubprogram(name: "wcslen", scope: !1972, file: !1972, line: 222, type: !2111, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2111 = !DISubroutineType(types: !2112)
+!2112 = !{!1678, !1773}
+!2113 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2114, file: !1966, line: 184)
+!2114 = !DISubprogram(name: "wcsncat", scope: !1986, file: !1986, line: 263, type: !2115, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2115 = !DISubroutineType(types: !2116)
+!2116 = !{!1726, !1725, !1772, !1678}
+!2117 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2118, file: !1966, line: 185)
+!2118 = !DISubprogram(name: "wcsncmp", scope: !1972, file: !1972, line: 109, type: !2119, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2119 = !DISubroutineType(types: !2120)
+!2120 = !{!93, !1773, !1773, !1678}
+!2121 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2122, file: !1966, line: 186)
+!2122 = !DISubprogram(name: "wcsncpy", scope: !1986, file: !1986, line: 191, type: !2115, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2123 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2124, file: !1966, line: 187)
+!2124 = !DISubprogram(name: "wcsrtombs", scope: !1986, file: !1986, line: 508, type: !2125, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2125 = !DISubroutineType(types: !2126)
+!2126 = !{!1678, !1771, !2127, !1678, !2018}
+!2127 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2128)
+!2128 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1773, size: 64)
+!2129 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2130, file: !1966, line: 188)
+!2130 = !DISubprogram(name: "wcsspn", scope: !1972, file: !1972, line: 191, type: !2099, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2131 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2132, file: !1966, line: 189)
+!2132 = !DISubprogram(name: "wcstod", scope: !1972, file: !1972, line: 377, type: !2133, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2133 = !DISubroutineType(types: !2134)
+!2134 = !{!1665, !1772, !2135}
+!2135 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2136)
+!2136 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1726, size: 64)
+!2137 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2138, file: !1966, line: 191)
+!2138 = !DISubprogram(name: "wcstof", scope: !1972, file: !1972, line: 382, type: !2139, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2139 = !DISubroutineType(types: !2140)
+!2140 = !{!1813, !1772, !2135}
+!2141 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2142, file: !1966, line: 193)
+!2142 = !DISubprogram(name: "wcstok", scope: !1972, file: !1972, line: 217, type: !2143, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2143 = !DISubroutineType(types: !2144)
+!2144 = !{!1726, !1725, !1772, !2135}
+!2145 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2146, file: !1966, line: 194)
+!2146 = !DISubprogram(name: "wcstol", scope: !1972, file: !1972, line: 428, type: !2147, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2147 = !DISubroutineType(types: !2148)
+!2148 = !{!1504, !1772, !2135, !93}
+!2149 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2150, file: !1966, line: 195)
+!2150 = !DISubprogram(name: "wcstoul", scope: !1972, file: !1972, line: 433, type: !2151, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2151 = !DISubroutineType(types: !2152)
+!2152 = !{!177, !1772, !2135, !93}
+!2153 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2154, file: !1966, line: 196)
+!2154 = !DISubprogram(name: "wcsxfrm", scope: !1972, file: !1972, line: 135, type: !2155, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2155 = !DISubroutineType(types: !2156)
+!2156 = !{!1678, !1725, !1772, !1678}
+!2157 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2158, file: !1966, line: 197)
+!2158 = !DISubprogram(name: "wctob", scope: !1972, file: !1972, line: 288, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2159 = !DISubroutineType(types: !2160)
+!2160 = !{!93, !1968}
+!2161 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2162, file: !1966, line: 198)
+!2162 = !DISubprogram(name: "wmemcmp", scope: !1972, file: !1972, line: 258, type: !2119, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2163 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2164, file: !1966, line: 199)
+!2164 = !DISubprogram(name: "wmemcpy", scope: !1986, file: !1986, line: 39, type: !2115, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2165 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2166, file: !1966, line: 200)
+!2166 = !DISubprogram(name: "wmemmove", scope: !1986, file: !1986, line: 68, type: !2167, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2167 = !DISubroutineType(types: !2168)
+!2168 = !{!1726, !1726, !1773, !1678}
+!2169 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2170, file: !1966, line: 201)
+!2170 = !DISubprogram(name: "wmemset", scope: !1986, file: !1986, line: 129, type: !2171, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2171 = !DISubroutineType(types: !2172)
+!2172 = !{!1726, !1726, !1727, !1678}
+!2173 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2174, file: !1966, line: 202)
+!2174 = !DISubprogram(name: "wprintf", scope: !1972, file: !1972, line: 587, type: !2175, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2175 = !DISubroutineType(types: !2176)
+!2176 = !{!93, !1772, null}
+!2177 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2178, file: !1966, line: 203)
+!2178 = !DISubprogram(name: "wscanf", scope: !1972, file: !1972, line: 628, type: !2175, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2179 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2180, file: !1966, line: 204)
+!2180 = !DISubprogram(name: "wcschr", scope: !1972, file: !1972, line: 164, type: !2181, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2181 = !DISubroutineType(types: !2182)
+!2182 = !{!1726, !1773, !1727}
+!2183 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2184, file: !1966, line: 205)
+!2184 = !DISubprogram(name: "wcspbrk", scope: !1972, file: !1972, line: 201, type: !2185, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2185 = !DISubroutineType(types: !2186)
+!2186 = !{!1726, !1773, !1773}
+!2187 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2188, file: !1966, line: 206)
+!2188 = !DISubprogram(name: "wcsrchr", scope: !1972, file: !1972, line: 174, type: !2181, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2189 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2190, file: !1966, line: 207)
+!2190 = !DISubprogram(name: "wcsstr", scope: !1972, file: !1972, line: 212, type: !2185, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2191 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2192, file: !1966, line: 208)
+!2192 = !DISubprogram(name: "wmemchr", scope: !1972, file: !1972, line: 253, type: !2193, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2193 = !DISubroutineType(types: !2194)
+!2194 = !{!1726, !1773, !1727, !1678}
+!2195 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2196, file: !1966, line: 248)
+!2196 = !DISubprogram(name: "wcstold", scope: !1972, file: !1972, line: 384, type: !2197, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2197 = !DISubroutineType(types: !2198)
+!2198 = !{!1818, !1772, !2135}
+!2199 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2200, file: !1966, line: 257)
+!2200 = !DISubprogram(name: "wcstoll", scope: !1972, file: !1972, line: 441, type: !2201, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2201 = !DISubroutineType(types: !2202)
+!2202 = !{!1784, !1772, !2135, !93}
+!2203 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2204, file: !1966, line: 258)
+!2204 = !DISubprogram(name: "wcstoull", scope: !1972, file: !1972, line: 448, type: !2205, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2205 = !DISubroutineType(types: !2206)
+!2206 = !{!1808, !1772, !2135, !93}
+!2207 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2196, file: !1966, line: 264)
+!2208 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2200, file: !1966, line: 265)
+!2209 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2204, file: !1966, line: 266)
+!2210 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2138, file: !1966, line: 280)
+!2211 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2066, file: !1966, line: 283)
+!2212 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2072, file: !1966, line: 286)
+!2213 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2080, file: !1966, line: 289)
+!2214 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2196, file: !1966, line: 293)
+!2215 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2200, file: !1966, line: 294)
+!2216 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2204, file: !1966, line: 295)
+!2217 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2218, file: !2222, line: 48)
+!2218 = !DIDerivedType(tag: DW_TAG_typedef, name: "int8_t", file: !2219, line: 24, baseType: !2220)
+!2219 = !DIFile(filename: "/usr/include/bits/stdint-intn.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2220 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int8_t", file: !46, line: 36, baseType: !2221)
+!2221 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char)
+!2222 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cstdint", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2223 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2224, file: !2222, line: 49)
+!2224 = !DIDerivedType(tag: DW_TAG_typedef, name: "int16_t", file: !2219, line: 25, baseType: !2225)
+!2225 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int16_t", file: !46, line: 38, baseType: !2226)
+!2226 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
+!2227 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2228, file: !2222, line: 50)
+!2228 = !DIDerivedType(tag: DW_TAG_typedef, name: "int32_t", file: !2219, line: 26, baseType: !2229)
+!2229 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int32_t", file: !46, line: 40, baseType: !93)
+!2230 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2231, file: !2222, line: 51)
+!2231 = !DIDerivedType(tag: DW_TAG_typedef, name: "int64_t", file: !2219, line: 27, baseType: !2232)
+!2232 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int64_t", file: !46, line: 43, baseType: !1504)
+!2233 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2234, file: !2222, line: 53)
+!2234 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_fast8_t", file: !2235, line: 58, baseType: !2221)
+!2235 = !DIFile(filename: "/usr/include/stdint.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2236 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2237, file: !2222, line: 54)
+!2237 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_fast16_t", file: !2235, line: 60, baseType: !1504)
+!2238 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2239, file: !2222, line: 55)
+!2239 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_fast32_t", file: !2235, line: 61, baseType: !1504)
+!2240 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2241, file: !2222, line: 56)
+!2241 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_fast64_t", file: !2235, line: 62, baseType: !1504)
+!2242 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2243, file: !2222, line: 58)
+!2243 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_least8_t", file: !2235, line: 43, baseType: !2244)
+!2244 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int_least8_t", file: !46, line: 51, baseType: !2220)
+!2245 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2246, file: !2222, line: 59)
+!2246 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_least16_t", file: !2235, line: 44, baseType: !2247)
+!2247 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int_least16_t", file: !46, line: 53, baseType: !2225)
+!2248 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2249, file: !2222, line: 60)
+!2249 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_least32_t", file: !2235, line: 45, baseType: !2250)
+!2250 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int_least32_t", file: !46, line: 55, baseType: !2229)
+!2251 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2252, file: !2222, line: 61)
+!2252 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_least64_t", file: !2235, line: 46, baseType: !2253)
+!2253 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int_least64_t", file: !46, line: 57, baseType: !2232)
+!2254 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2255, file: !2222, line: 63)
+!2255 = !DIDerivedType(tag: DW_TAG_typedef, name: "intmax_t", file: !2235, line: 101, baseType: !2256)
+!2256 = !DIDerivedType(tag: DW_TAG_typedef, name: "__intmax_t", file: !46, line: 71, baseType: !1504)
+!2257 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2258, file: !2222, line: 64)
+!2258 = !DIDerivedType(tag: DW_TAG_typedef, name: "intptr_t", file: !2235, line: 87, baseType: !1504)
+!2259 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2260, file: !2222, line: 66)
+!2260 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint8_t", file: !44, line: 24, baseType: !2261)
+!2261 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint8_t", file: !46, line: 37, baseType: !491)
+!2262 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2263, file: !2222, line: 67)
+!2263 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint16_t", file: !44, line: 25, baseType: !2264)
+!2264 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint16_t", file: !46, line: 39, baseType: !2265)
+!2265 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned)
+!2266 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !43, file: !2222, line: 68)
+!2267 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2268, file: !2222, line: 69)
+!2268 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint64_t", file: !44, line: 27, baseType: !2269)
+!2269 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint64_t", file: !46, line: 44, baseType: !177)
+!2270 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2271, file: !2222, line: 71)
+!2271 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_fast8_t", file: !2235, line: 71, baseType: !491)
+!2272 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2273, file: !2222, line: 72)
+!2273 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_fast16_t", file: !2235, line: 73, baseType: !177)
+!2274 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2275, file: !2222, line: 73)
+!2275 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_fast32_t", file: !2235, line: 74, baseType: !177)
+!2276 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2277, file: !2222, line: 74)
+!2277 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_fast64_t", file: !2235, line: 75, baseType: !177)
+!2278 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2279, file: !2222, line: 76)
+!2279 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_least8_t", file: !2235, line: 49, baseType: !2280)
+!2280 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint_least8_t", file: !46, line: 52, baseType: !2261)
+!2281 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2282, file: !2222, line: 77)
+!2282 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_least16_t", file: !2235, line: 50, baseType: !2283)
+!2283 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint_least16_t", file: !46, line: 54, baseType: !2264)
+!2284 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2285, file: !2222, line: 78)
+!2285 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_least32_t", file: !2235, line: 51, baseType: !2286)
+!2286 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint_least32_t", file: !46, line: 56, baseType: !45)
+!2287 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2288, file: !2222, line: 79)
+!2288 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint_least64_t", file: !2235, line: 52, baseType: !2289)
+!2289 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint_least64_t", file: !46, line: 58, baseType: !2269)
+!2290 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2291, file: !2222, line: 81)
+!2291 = !DIDerivedType(tag: DW_TAG_typedef, name: "uintmax_t", file: !2235, line: 102, baseType: !2292)
+!2292 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uintmax_t", file: !46, line: 72, baseType: !177)
+!2293 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2294, file: !2222, line: 82)
+!2294 = !DIDerivedType(tag: DW_TAG_typedef, name: "uintptr_t", file: !2235, line: 90, baseType: !177)
+!2295 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !175, file: !147, line: 44)
+!2296 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !1503, file: !147, line: 45)
+!2297 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2298, file: !2300, line: 53)
+!2298 = !DICompositeType(tag: DW_TAG_structure_type, name: "lconv", file: !2299, line: 51, flags: DIFlagFwdDecl, identifier: "_ZTS5lconv")
+!2299 = !DIFile(filename: "/usr/include/locale.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2300 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/clocale", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2301 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2302, file: !2300, line: 54)
+!2302 = !DISubprogram(name: "setlocale", scope: !2299, file: !2299, line: 122, type: !2303, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2303 = !DISubroutineType(types: !2304)
+!2304 = !{!1170, !93, !1443}
+!2305 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2306, file: !2300, line: 55)
+!2306 = !DISubprogram(name: "localeconv", scope: !2299, file: !2299, line: 125, type: !2307, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2307 = !DISubroutineType(types: !2308)
+!2308 = !{!2309}
+!2309 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2298, size: 64)
+!2310 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2311, file: !2313, line: 64)
+!2311 = !DISubprogram(name: "isalnum", scope: !2312, file: !2312, line: 108, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2312 = !DIFile(filename: "/usr/include/ctype.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2313 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cctype", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2314 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2315, file: !2313, line: 65)
+!2315 = !DISubprogram(name: "isalpha", scope: !2312, file: !2312, line: 109, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2316 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2317, file: !2313, line: 66)
+!2317 = !DISubprogram(name: "iscntrl", scope: !2312, file: !2312, line: 110, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2318 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2319, file: !2313, line: 67)
+!2319 = !DISubprogram(name: "isdigit", scope: !2312, file: !2312, line: 111, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2320 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2321, file: !2313, line: 68)
+!2321 = !DISubprogram(name: "isgraph", scope: !2312, file: !2312, line: 113, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2322 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2323, file: !2313, line: 69)
+!2323 = !DISubprogram(name: "islower", scope: !2312, file: !2312, line: 112, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2324 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2325, file: !2313, line: 70)
+!2325 = !DISubprogram(name: "isprint", scope: !2312, file: !2312, line: 114, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2326 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2327, file: !2313, line: 71)
+!2327 = !DISubprogram(name: "ispunct", scope: !2312, file: !2312, line: 115, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2328 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2329, file: !2313, line: 72)
+!2329 = !DISubprogram(name: "isspace", scope: !2312, file: !2312, line: 116, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2330 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2331, file: !2313, line: 73)
+!2331 = !DISubprogram(name: "isupper", scope: !2312, file: !2312, line: 117, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2332 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2333, file: !2313, line: 74)
+!2333 = !DISubprogram(name: "isxdigit", scope: !2312, file: !2312, line: 118, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2334 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2335, file: !2313, line: 75)
+!2335 = !DISubprogram(name: "tolower", scope: !2312, file: !2312, line: 122, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2336 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2337, file: !2313, line: 76)
+!2337 = !DISubprogram(name: "toupper", scope: !2312, file: !2312, line: 125, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2338 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2339, file: !2313, line: 87)
+!2339 = !DISubprogram(name: "isblank", scope: !2312, file: !2312, line: 130, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2340 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2341, file: !2343, line: 98)
+!2341 = !DIDerivedType(tag: DW_TAG_typedef, name: "FILE", file: !2342, line: 7, baseType: !1982)
+!2342 = !DIFile(filename: "/usr/include/bits/types/FILE.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2343 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cstdio", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2344 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2345, file: !2343, line: 99)
+!2345 = !DIDerivedType(tag: DW_TAG_typedef, name: "fpos_t", file: !2346, line: 84, baseType: !2347)
+!2346 = !DIFile(filename: "/usr/include/stdio.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2347 = !DIDerivedType(tag: DW_TAG_typedef, name: "__fpos_t", file: !2348, line: 14, baseType: !2349)
+!2348 = !DIFile(filename: "/usr/include/bits/types/__fpos_t.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2349 = !DICompositeType(tag: DW_TAG_structure_type, name: "_G_fpos_t", file: !2348, line: 10, flags: DIFlagFwdDecl, identifier: "_ZTS9_G_fpos_t")
+!2350 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2351, file: !2343, line: 101)
+!2351 = !DISubprogram(name: "clearerr", scope: !2346, file: !2346, line: 763, type: !2352, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2352 = !DISubroutineType(types: !2353)
+!2353 = !{null, !2354}
+!2354 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2341, size: 64)
+!2355 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2356, file: !2343, line: 102)
+!2356 = !DISubprogram(name: "fclose", scope: !2346, file: !2346, line: 213, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2357 = !DISubroutineType(types: !2358)
+!2358 = !{!93, !2354}
+!2359 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2360, file: !2343, line: 103)
+!2360 = !DISubprogram(name: "feof", scope: !2346, file: !2346, line: 765, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2361 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2362, file: !2343, line: 104)
+!2362 = !DISubprogram(name: "ferror", scope: !2346, file: !2346, line: 767, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2363 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2364, file: !2343, line: 105)
+!2364 = !DISubprogram(name: "fflush", scope: !2346, file: !2346, line: 218, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2365 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2366, file: !2343, line: 106)
+!2366 = !DISubprogram(name: "fgetc", scope: !2346, file: !2346, line: 491, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2367 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2368, file: !2343, line: 107)
+!2368 = !DISubprogram(name: "fgetpos", scope: !2346, file: !2346, line: 737, type: !2369, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2369 = !DISubroutineType(types: !2370)
+!2370 = !{!93, !2371, !2372}
+!2371 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2354)
+!2372 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !2373)
+!2373 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2345, size: 64)
+!2374 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2375, file: !2343, line: 108)
+!2375 = !DISubprogram(name: "fgets", scope: !2376, file: !2376, line: 255, type: !2377, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2376 = !DIFile(filename: "/usr/include/bits/stdio2.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2377 = !DISubroutineType(types: !2378)
+!2378 = !{!1170, !1771, !93, !2371}
+!2379 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2380, file: !2343, line: 109)
+!2380 = !DISubprogram(name: "fopen", scope: !2346, file: !2346, line: 246, type: !2381, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2381 = !DISubroutineType(types: !2382)
+!2382 = !{!2354, !1728, !1728}
+!2383 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2384, file: !2343, line: 110)
+!2384 = !DISubprogram(name: "fprintf", scope: !2346, file: !2346, line: 326, type: !2385, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2385 = !DISubroutineType(types: !2386)
+!2386 = !{!93, !2371, !1728, null}
+!2387 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2388, file: !2343, line: 111)
+!2388 = !DISubprogram(name: "fputc", scope: !2346, file: !2346, line: 527, type: !2389, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2389 = !DISubroutineType(types: !2390)
+!2390 = !{!93, !93, !2354}
+!2391 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2392, file: !2343, line: 112)
+!2392 = !DISubprogram(name: "fputs", scope: !2346, file: !2346, line: 632, type: !2393, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2393 = !DISubroutineType(types: !2394)
+!2394 = !{!93, !1728, !2371}
+!2395 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2396, file: !2343, line: 113)
+!2396 = !DISubprogram(name: "fread", scope: !2376, file: !2376, line: 284, type: !2397, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2397 = !DISubroutineType(types: !2398)
+!2398 = !{!1678, !1882, !1678, !1678, !2371}
+!2399 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2400, file: !2343, line: 114)
+!2400 = !DISubprogram(name: "freopen", scope: !2346, file: !2346, line: 252, type: !2401, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2401 = !DISubroutineType(types: !2402)
+!2402 = !{!2354, !1728, !1728, !2371}
+!2403 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2404, file: !2343, line: 115)
+!2404 = !DISubprogram(name: "fscanf", scope: !2346, file: !2346, line: 391, type: !2385, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2405 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2406, file: !2343, line: 116)
+!2406 = !DISubprogram(name: "fseek", scope: !2346, file: !2346, line: 690, type: !2407, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2407 = !DISubroutineType(types: !2408)
+!2408 = !{!93, !2354, !1504, !93}
+!2409 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2410, file: !2343, line: 117)
+!2410 = !DISubprogram(name: "fsetpos", scope: !2346, file: !2346, line: 742, type: !2411, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2411 = !DISubroutineType(types: !2412)
+!2412 = !{!93, !2354, !2413}
+!2413 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2414, size: 64)
+!2414 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2345)
+!2415 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2416, file: !2343, line: 118)
+!2416 = !DISubprogram(name: "ftell", scope: !2346, file: !2346, line: 695, type: !2417, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2417 = !DISubroutineType(types: !2418)
+!2418 = !{!1504, !2354}
+!2419 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2420, file: !2343, line: 119)
+!2420 = !DISubprogram(name: "fwrite", scope: !2346, file: !2346, line: 658, type: !2421, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2421 = !DISubroutineType(types: !2422)
+!2422 = !{!1678, !1883, !1678, !1678, !2371}
+!2423 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2424, file: !2343, line: 120)
+!2424 = !DISubprogram(name: "getc", scope: !2346, file: !2346, line: 492, type: !2357, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2425 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2426, file: !2343, line: 121)
+!2426 = !DISubprogram(name: "getchar", scope: !2346, file: !2346, line: 498, type: !1741, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2427 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2428, file: !2343, line: 126)
+!2428 = !DISubprogram(name: "perror", scope: !2346, file: !2346, line: 781, type: !2429, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2429 = !DISubroutineType(types: !2430)
+!2430 = !{null, !1443}
+!2431 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2432, file: !2343, line: 127)
+!2432 = !DISubprogram(name: "printf", scope: !2346, file: !2346, line: 332, type: !2433, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2433 = !DISubroutineType(types: !2434)
+!2434 = !{!93, !1728, null}
+!2435 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2436, file: !2343, line: 128)
+!2436 = !DISubprogram(name: "putc", scope: !2346, file: !2346, line: 528, type: !2389, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2437 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2438, file: !2343, line: 129)
+!2438 = !DISubprogram(name: "putchar", scope: !2346, file: !2346, line: 534, type: !1637, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2439 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2440, file: !2343, line: 130)
+!2440 = !DISubprogram(name: "puts", scope: !2346, file: !2346, line: 638, type: !1668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2441 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2442, file: !2343, line: 131)
+!2442 = !DISubprogram(name: "remove", scope: !2346, file: !2346, line: 146, type: !1668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2443 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2444, file: !2343, line: 132)
+!2444 = !DISubprogram(name: "rename", scope: !2346, file: !2346, line: 148, type: !1898, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2445 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2446, file: !2343, line: 133)
+!2446 = !DISubprogram(name: "rewind", scope: !2346, file: !2346, line: 700, type: !2352, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2447 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2448, file: !2343, line: 134)
+!2448 = !DISubprogram(name: "scanf", scope: !2346, file: !2346, line: 397, type: !2433, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2449 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2450, file: !2343, line: 135)
+!2450 = !DISubprogram(name: "setbuf", scope: !2346, file: !2346, line: 304, type: !2451, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2451 = !DISubroutineType(types: !2452)
+!2452 = !{null, !2371, !1771}
+!2453 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2454, file: !2343, line: 136)
+!2454 = !DISubprogram(name: "setvbuf", scope: !2346, file: !2346, line: 308, type: !2455, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2455 = !DISubroutineType(types: !2456)
+!2456 = !{!93, !2371, !1771, !93, !1678}
+!2457 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2458, file: !2343, line: 137)
+!2458 = !DISubprogram(name: "sprintf", scope: !2346, file: !2346, line: 334, type: !2459, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2459 = !DISubroutineType(types: !2460)
+!2460 = !{!93, !1771, !1728, null}
+!2461 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2462, file: !2343, line: 138)
+!2462 = !DISubprogram(name: "sscanf", scope: !2346, file: !2346, line: 399, type: !2463, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2463 = !DISubroutineType(types: !2464)
+!2464 = !{!93, !1728, !1728, null}
+!2465 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2466, file: !2343, line: 139)
+!2466 = !DISubprogram(name: "tmpfile", scope: !2346, file: !2346, line: 173, type: !2467, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2467 = !DISubroutineType(types: !2468)
+!2468 = !{!2354}
+!2469 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2470, file: !2343, line: 141)
+!2470 = !DISubprogram(name: "tmpnam", scope: !2346, file: !2346, line: 187, type: !2471, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2471 = !DISubroutineType(types: !2472)
+!2472 = !{!1170, !1170}
+!2473 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2474, file: !2343, line: 143)
+!2474 = !DISubprogram(name: "ungetc", scope: !2346, file: !2346, line: 645, type: !2389, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2475 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2476, file: !2343, line: 144)
+!2476 = !DISubprogram(name: "vfprintf", scope: !2376, file: !2376, line: 127, type: !2477, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2477 = !DISubroutineType(types: !2478)
+!2478 = !{!93, !2371, !1728, !2058}
+!2479 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2480, file: !2343, line: 145)
+!2480 = !DISubprogram(name: "vprintf", scope: !2376, file: !2376, line: 117, type: !2481, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2481 = !DISubroutineType(types: !2482)
+!2482 = !{!93, !1728, !2058}
+!2483 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2484, file: !2343, line: 146)
+!2484 = !DISubprogram(name: "vsprintf", scope: !2376, file: !2376, line: 46, type: !2485, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2485 = !DISubroutineType(types: !2486)
+!2486 = !{!93, !1771, !1728, !2058}
+!2487 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2488, file: !2343, line: 175)
+!2488 = !DISubprogram(name: "snprintf", scope: !2346, file: !2346, line: 354, type: !2489, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2489 = !DISubroutineType(types: !2490)
+!2490 = !{!93, !1771, !1678, !1728, null}
+!2491 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2492, file: !2343, line: 176)
+!2492 = !DISubprogram(name: "vfscanf", scope: !2346, file: !2346, line: 434, type: !2477, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2493 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2494, file: !2343, line: 177)
+!2494 = !DISubprogram(name: "vscanf", scope: !2346, file: !2346, line: 442, type: !2481, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2495 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2496, file: !2343, line: 178)
+!2496 = !DISubprogram(name: "vsnprintf", scope: !2376, file: !2376, line: 77, type: !2497, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2497 = !DISubroutineType(types: !2498)
+!2498 = !{!93, !1771, !1678, !1728, !2058}
+!2499 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !2500, file: !2343, line: 179)
+!2500 = !DISubprogram(name: "vsscanf", scope: !2346, file: !2346, line: 446, type: !2501, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2501 = !DISubroutineType(types: !2502)
+!2502 = !{!93, !1728, !1728, !2058}
+!2503 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2488, file: !2343, line: 185)
+!2504 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2492, file: !2343, line: 186)
+!2505 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2494, file: !2343, line: 187)
+!2506 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2496, file: !2343, line: 188)
+!2507 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2500, file: !2343, line: 189)
+!2508 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2509, file: !2513, line: 82)
+!2509 = !DIDerivedType(tag: DW_TAG_typedef, name: "wctrans_t", file: !2510, line: 48, baseType: !2511)
+!2510 = !DIFile(filename: "/usr/include/wctype.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2511 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2512, size: 64)
+!2512 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2229)
+!2513 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cwctype", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2514 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2515, file: !2513, line: 83)
+!2515 = !DIDerivedType(tag: DW_TAG_typedef, name: "wctype_t", file: !2516, line: 38, baseType: !177)
+!2516 = !DIFile(filename: "/usr/include/bits/wctype-wchar.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2517 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !1968, file: !2513, line: 84)
+!2518 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2519, file: !2513, line: 86)
+!2519 = !DISubprogram(name: "iswalnum", scope: !2516, file: !2516, line: 95, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2520 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2521, file: !2513, line: 87)
+!2521 = !DISubprogram(name: "iswalpha", scope: !2516, file: !2516, line: 101, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2522 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2523, file: !2513, line: 89)
+!2523 = !DISubprogram(name: "iswblank", scope: !2516, file: !2516, line: 146, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2524 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2525, file: !2513, line: 91)
+!2525 = !DISubprogram(name: "iswcntrl", scope: !2516, file: !2516, line: 104, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2526 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2527, file: !2513, line: 92)
+!2527 = !DISubprogram(name: "iswctype", scope: !2516, file: !2516, line: 159, type: !2528, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2528 = !DISubroutineType(types: !2529)
+!2529 = !{!93, !1968, !2515}
+!2530 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2531, file: !2513, line: 93)
+!2531 = !DISubprogram(name: "iswdigit", scope: !2516, file: !2516, line: 108, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2532 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2533, file: !2513, line: 94)
+!2533 = !DISubprogram(name: "iswgraph", scope: !2516, file: !2516, line: 112, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2534 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2535, file: !2513, line: 95)
+!2535 = !DISubprogram(name: "iswlower", scope: !2516, file: !2516, line: 117, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2536 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2537, file: !2513, line: 96)
+!2537 = !DISubprogram(name: "iswprint", scope: !2516, file: !2516, line: 120, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2538 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2539, file: !2513, line: 97)
+!2539 = !DISubprogram(name: "iswpunct", scope: !2516, file: !2516, line: 125, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2540 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2541, file: !2513, line: 98)
+!2541 = !DISubprogram(name: "iswspace", scope: !2516, file: !2516, line: 130, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2542 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2543, file: !2513, line: 99)
+!2543 = !DISubprogram(name: "iswupper", scope: !2516, file: !2516, line: 135, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2544 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2545, file: !2513, line: 100)
+!2545 = !DISubprogram(name: "iswxdigit", scope: !2516, file: !2516, line: 140, type: !2159, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2546 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2547, file: !2513, line: 101)
+!2547 = !DISubprogram(name: "towctrans", scope: !2510, file: !2510, line: 55, type: !2548, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2548 = !DISubroutineType(types: !2549)
+!2549 = !{!1968, !1968, !2509}
+!2550 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2551, file: !2513, line: 102)
+!2551 = !DISubprogram(name: "towlower", scope: !2516, file: !2516, line: 166, type: !2552, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2552 = !DISubroutineType(types: !2553)
+!2553 = !{!1968, !1968}
+!2554 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2555, file: !2513, line: 103)
+!2555 = !DISubprogram(name: "towupper", scope: !2516, file: !2516, line: 169, type: !2552, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2556 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2557, file: !2513, line: 104)
+!2557 = !DISubprogram(name: "wctrans", scope: !2510, file: !2510, line: 52, type: !2558, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2558 = !DISubroutineType(types: !2559)
+!2559 = !{!2509, !1443}
+!2560 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2561, file: !2513, line: 105)
+!2561 = !DISubprogram(name: "wctype", scope: !2516, file: !2516, line: 155, type: !2562, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2562 = !DISubroutineType(types: !2563)
+!2563 = !{!2515, !1443}
+!2564 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !3, file: !2565, line: 86)
+!2565 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/shared_ptr_base.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2566 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2567, file: !2565, line: 87)
+!2567 = !DIGlobalVariable(name: "__default_lock_policy", linkageName: "_ZN9__gnu_cxxL21__default_lock_policyE", scope: !5, file: !4, line: 53, type: !2568, isLocal: true, isDefinition: false)
+!2568 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3)
+!2569 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2570, file: !2574, line: 83)
+!2570 = !DISubprogram(name: "acos", scope: !2571, file: !2571, line: 53, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2571 = !DIFile(filename: "/usr/include/bits/mathcalls.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2572 = !DISubroutineType(types: !2573)
+!2573 = !{!1665, !1665}
+!2574 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/cmath", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2575 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2576, file: !2574, line: 102)
+!2576 = !DISubprogram(name: "asin", scope: !2571, file: !2571, line: 55, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2577 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2578, file: !2574, line: 121)
+!2578 = !DISubprogram(name: "atan", scope: !2571, file: !2571, line: 57, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2579 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2580, file: !2574, line: 140)
+!2580 = !DISubprogram(name: "atan2", scope: !2571, file: !2571, line: 59, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2581 = !DISubroutineType(types: !2582)
+!2582 = !{!1665, !1665, !1665}
+!2583 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2584, file: !2574, line: 161)
+!2584 = !DISubprogram(name: "ceil", scope: !2571, file: !2571, line: 159, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2585 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2586, file: !2574, line: 180)
+!2586 = !DISubprogram(name: "cos", scope: !2571, file: !2571, line: 62, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2587 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2588, file: !2574, line: 199)
+!2588 = !DISubprogram(name: "cosh", scope: !2571, file: !2571, line: 71, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2589 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2590, file: !2574, line: 218)
+!2590 = !DISubprogram(name: "exp", scope: !2571, file: !2571, line: 95, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2591 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2592, file: !2574, line: 237)
+!2592 = !DISubprogram(name: "fabs", scope: !2571, file: !2571, line: 162, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2593 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2594, file: !2574, line: 256)
+!2594 = !DISubprogram(name: "floor", scope: !2571, file: !2571, line: 165, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2595 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2596, file: !2574, line: 275)
+!2596 = !DISubprogram(name: "fmod", scope: !2571, file: !2571, line: 168, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2597 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2598, file: !2574, line: 296)
+!2598 = !DISubprogram(name: "frexp", scope: !2571, file: !2571, line: 98, type: !2599, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2599 = !DISubroutineType(types: !2600)
+!2600 = !{!1665, !1665, !2601}
+!2601 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !93, size: 64)
+!2602 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2603, file: !2574, line: 315)
+!2603 = !DISubprogram(name: "ldexp", scope: !2571, file: !2571, line: 101, type: !2604, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2604 = !DISubroutineType(types: !2605)
+!2605 = !{!1665, !1665, !93}
+!2606 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2607, file: !2574, line: 334)
+!2607 = !DISubprogram(name: "log", scope: !2571, file: !2571, line: 104, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2608 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2609, file: !2574, line: 353)
+!2609 = !DISubprogram(name: "log10", scope: !2571, file: !2571, line: 107, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2610 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2611, file: !2574, line: 372)
+!2611 = !DISubprogram(name: "modf", scope: !2571, file: !2571, line: 110, type: !2612, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2612 = !DISubroutineType(types: !2613)
+!2613 = !{!1665, !1665, !2614}
+!2614 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1665, size: 64)
+!2615 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2616, file: !2574, line: 384)
+!2616 = !DISubprogram(name: "pow", scope: !2571, file: !2571, line: 140, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2617 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2618, file: !2574, line: 421)
+!2618 = !DISubprogram(name: "sin", scope: !2571, file: !2571, line: 64, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2619 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2620, file: !2574, line: 440)
+!2620 = !DISubprogram(name: "sinh", scope: !2571, file: !2571, line: 73, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2621 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2622, file: !2574, line: 459)
+!2622 = !DISubprogram(name: "sqrt", scope: !2571, file: !2571, line: 143, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2623 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2624, file: !2574, line: 478)
+!2624 = !DISubprogram(name: "tan", scope: !2571, file: !2571, line: 66, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2625 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2626, file: !2574, line: 497)
+!2626 = !DISubprogram(name: "tanh", scope: !2571, file: !2571, line: 75, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2627 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2628, file: !2574, line: 1065)
+!2628 = !DIDerivedType(tag: DW_TAG_typedef, name: "double_t", file: !2629, line: 150, baseType: !1665)
+!2629 = !DIFile(filename: "/usr/include/math.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2630 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2631, file: !2574, line: 1066)
+!2631 = !DIDerivedType(tag: DW_TAG_typedef, name: "float_t", file: !2629, line: 149, baseType: !1813)
+!2632 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2633, file: !2574, line: 1069)
+!2633 = !DISubprogram(name: "acosh", scope: !2571, file: !2571, line: 85, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2634 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2635, file: !2574, line: 1070)
+!2635 = !DISubprogram(name: "acoshf", scope: !2571, file: !2571, line: 85, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2636 = !DISubroutineType(types: !2637)
+!2637 = !{!1813, !1813}
+!2638 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2639, file: !2574, line: 1071)
+!2639 = !DISubprogram(name: "acoshl", scope: !2571, file: !2571, line: 85, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2640 = !DISubroutineType(types: !2641)
+!2641 = !{!1818, !1818}
+!2642 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2643, file: !2574, line: 1073)
+!2643 = !DISubprogram(name: "asinh", scope: !2571, file: !2571, line: 87, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2644 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2645, file: !2574, line: 1074)
+!2645 = !DISubprogram(name: "asinhf", scope: !2571, file: !2571, line: 87, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2646 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2647, file: !2574, line: 1075)
+!2647 = !DISubprogram(name: "asinhl", scope: !2571, file: !2571, line: 87, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2648 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2649, file: !2574, line: 1077)
+!2649 = !DISubprogram(name: "atanh", scope: !2571, file: !2571, line: 89, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2650 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2651, file: !2574, line: 1078)
+!2651 = !DISubprogram(name: "atanhf", scope: !2571, file: !2571, line: 89, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2652 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2653, file: !2574, line: 1079)
+!2653 = !DISubprogram(name: "atanhl", scope: !2571, file: !2571, line: 89, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2654 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2655, file: !2574, line: 1081)
+!2655 = !DISubprogram(name: "cbrt", scope: !2571, file: !2571, line: 152, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2656 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2657, file: !2574, line: 1082)
+!2657 = !DISubprogram(name: "cbrtf", scope: !2571, file: !2571, line: 152, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2658 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2659, file: !2574, line: 1083)
+!2659 = !DISubprogram(name: "cbrtl", scope: !2571, file: !2571, line: 152, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2660 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2661, file: !2574, line: 1085)
+!2661 = !DISubprogram(name: "copysign", scope: !2571, file: !2571, line: 196, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2662 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2663, file: !2574, line: 1086)
+!2663 = !DISubprogram(name: "copysignf", scope: !2571, file: !2571, line: 196, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2664 = !DISubroutineType(types: !2665)
+!2665 = !{!1813, !1813, !1813}
+!2666 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2667, file: !2574, line: 1087)
+!2667 = !DISubprogram(name: "copysignl", scope: !2571, file: !2571, line: 196, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2668 = !DISubroutineType(types: !2669)
+!2669 = !{!1818, !1818, !1818}
+!2670 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2671, file: !2574, line: 1089)
+!2671 = !DISubprogram(name: "erf", scope: !2571, file: !2571, line: 228, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2672 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2673, file: !2574, line: 1090)
+!2673 = !DISubprogram(name: "erff", scope: !2571, file: !2571, line: 228, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2674 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2675, file: !2574, line: 1091)
+!2675 = !DISubprogram(name: "erfl", scope: !2571, file: !2571, line: 228, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2676 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2677, file: !2574, line: 1093)
+!2677 = !DISubprogram(name: "erfc", scope: !2571, file: !2571, line: 229, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2678 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2679, file: !2574, line: 1094)
+!2679 = !DISubprogram(name: "erfcf", scope: !2571, file: !2571, line: 229, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2680 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2681, file: !2574, line: 1095)
+!2681 = !DISubprogram(name: "erfcl", scope: !2571, file: !2571, line: 229, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2682 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2683, file: !2574, line: 1097)
+!2683 = !DISubprogram(name: "exp2", scope: !2571, file: !2571, line: 130, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2684 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2685, file: !2574, line: 1098)
+!2685 = !DISubprogram(name: "exp2f", scope: !2571, file: !2571, line: 130, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2686 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2687, file: !2574, line: 1099)
+!2687 = !DISubprogram(name: "exp2l", scope: !2571, file: !2571, line: 130, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2688 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2689, file: !2574, line: 1101)
+!2689 = !DISubprogram(name: "expm1", scope: !2571, file: !2571, line: 119, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2690 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2691, file: !2574, line: 1102)
+!2691 = !DISubprogram(name: "expm1f", scope: !2571, file: !2571, line: 119, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2692 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2693, file: !2574, line: 1103)
+!2693 = !DISubprogram(name: "expm1l", scope: !2571, file: !2571, line: 119, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2694 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2695, file: !2574, line: 1105)
+!2695 = !DISubprogram(name: "fdim", scope: !2571, file: !2571, line: 326, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2696 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2697, file: !2574, line: 1106)
+!2697 = !DISubprogram(name: "fdimf", scope: !2571, file: !2571, line: 326, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2698 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2699, file: !2574, line: 1107)
+!2699 = !DISubprogram(name: "fdiml", scope: !2571, file: !2571, line: 326, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2700 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2701, file: !2574, line: 1109)
+!2701 = !DISubprogram(name: "fma", scope: !2571, file: !2571, line: 335, type: !2702, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2702 = !DISubroutineType(types: !2703)
+!2703 = !{!1665, !1665, !1665, !1665}
+!2704 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2705, file: !2574, line: 1110)
+!2705 = !DISubprogram(name: "fmaf", scope: !2571, file: !2571, line: 335, type: !2706, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2706 = !DISubroutineType(types: !2707)
+!2707 = !{!1813, !1813, !1813, !1813}
+!2708 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2709, file: !2574, line: 1111)
+!2709 = !DISubprogram(name: "fmal", scope: !2571, file: !2571, line: 335, type: !2710, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2710 = !DISubroutineType(types: !2711)
+!2711 = !{!1818, !1818, !1818, !1818}
+!2712 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2713, file: !2574, line: 1113)
+!2713 = !DISubprogram(name: "fmax", scope: !2571, file: !2571, line: 329, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2714 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2715, file: !2574, line: 1114)
+!2715 = !DISubprogram(name: "fmaxf", scope: !2571, file: !2571, line: 329, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2716 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2717, file: !2574, line: 1115)
+!2717 = !DISubprogram(name: "fmaxl", scope: !2571, file: !2571, line: 329, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2718 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2719, file: !2574, line: 1117)
+!2719 = !DISubprogram(name: "fmin", scope: !2571, file: !2571, line: 332, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2720 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2721, file: !2574, line: 1118)
+!2721 = !DISubprogram(name: "fminf", scope: !2571, file: !2571, line: 332, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2722 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2723, file: !2574, line: 1119)
+!2723 = !DISubprogram(name: "fminl", scope: !2571, file: !2571, line: 332, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2724 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2725, file: !2574, line: 1121)
+!2725 = !DISubprogram(name: "hypot", scope: !2571, file: !2571, line: 147, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2726 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2727, file: !2574, line: 1122)
+!2727 = !DISubprogram(name: "hypotf", scope: !2571, file: !2571, line: 147, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2728 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2729, file: !2574, line: 1123)
+!2729 = !DISubprogram(name: "hypotl", scope: !2571, file: !2571, line: 147, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2730 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2731, file: !2574, line: 1125)
+!2731 = !DISubprogram(name: "ilogb", scope: !2571, file: !2571, line: 280, type: !2732, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2732 = !DISubroutineType(types: !2733)
+!2733 = !{!93, !1665}
+!2734 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2735, file: !2574, line: 1126)
+!2735 = !DISubprogram(name: "ilogbf", scope: !2571, file: !2571, line: 280, type: !2736, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2736 = !DISubroutineType(types: !2737)
+!2737 = !{!93, !1813}
+!2738 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2739, file: !2574, line: 1127)
+!2739 = !DISubprogram(name: "ilogbl", scope: !2571, file: !2571, line: 280, type: !2740, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2740 = !DISubroutineType(types: !2741)
+!2741 = !{!93, !1818}
+!2742 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2743, file: !2574, line: 1129)
+!2743 = !DISubprogram(name: "lgamma", scope: !2571, file: !2571, line: 230, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2744 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2745, file: !2574, line: 1130)
+!2745 = !DISubprogram(name: "lgammaf", scope: !2571, file: !2571, line: 230, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2746 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2747, file: !2574, line: 1131)
+!2747 = !DISubprogram(name: "lgammal", scope: !2571, file: !2571, line: 230, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2748 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2749, file: !2574, line: 1134)
+!2749 = !DISubprogram(name: "llrint", scope: !2571, file: !2571, line: 316, type: !2750, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2750 = !DISubroutineType(types: !2751)
+!2751 = !{!1784, !1665}
+!2752 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2753, file: !2574, line: 1135)
+!2753 = !DISubprogram(name: "llrintf", scope: !2571, file: !2571, line: 316, type: !2754, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2754 = !DISubroutineType(types: !2755)
+!2755 = !{!1784, !1813}
+!2756 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2757, file: !2574, line: 1136)
+!2757 = !DISubprogram(name: "llrintl", scope: !2571, file: !2571, line: 316, type: !2758, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2758 = !DISubroutineType(types: !2759)
+!2759 = !{!1784, !1818}
+!2760 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2761, file: !2574, line: 1138)
+!2761 = !DISubprogram(name: "llround", scope: !2571, file: !2571, line: 322, type: !2750, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2762 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2763, file: !2574, line: 1139)
+!2763 = !DISubprogram(name: "llroundf", scope: !2571, file: !2571, line: 322, type: !2754, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2764 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2765, file: !2574, line: 1140)
+!2765 = !DISubprogram(name: "llroundl", scope: !2571, file: !2571, line: 322, type: !2758, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2766 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2767, file: !2574, line: 1143)
+!2767 = !DISubprogram(name: "log1p", scope: !2571, file: !2571, line: 122, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2768 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2769, file: !2574, line: 1144)
+!2769 = !DISubprogram(name: "log1pf", scope: !2571, file: !2571, line: 122, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2770 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2771, file: !2574, line: 1145)
+!2771 = !DISubprogram(name: "log1pl", scope: !2571, file: !2571, line: 122, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2772 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2773, file: !2574, line: 1147)
+!2773 = !DISubprogram(name: "log2", scope: !2571, file: !2571, line: 133, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2774 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2775, file: !2574, line: 1148)
+!2775 = !DISubprogram(name: "log2f", scope: !2571, file: !2571, line: 133, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2776 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2777, file: !2574, line: 1149)
+!2777 = !DISubprogram(name: "log2l", scope: !2571, file: !2571, line: 133, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2778 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2779, file: !2574, line: 1151)
+!2779 = !DISubprogram(name: "logb", scope: !2571, file: !2571, line: 125, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2780 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2781, file: !2574, line: 1152)
+!2781 = !DISubprogram(name: "logbf", scope: !2571, file: !2571, line: 125, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2782 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2783, file: !2574, line: 1153)
+!2783 = !DISubprogram(name: "logbl", scope: !2571, file: !2571, line: 125, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2784 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2785, file: !2574, line: 1155)
+!2785 = !DISubprogram(name: "lrint", scope: !2571, file: !2571, line: 314, type: !2786, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2786 = !DISubroutineType(types: !2787)
+!2787 = !{!1504, !1665}
+!2788 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2789, file: !2574, line: 1156)
+!2789 = !DISubprogram(name: "lrintf", scope: !2571, file: !2571, line: 314, type: !2790, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2790 = !DISubroutineType(types: !2791)
+!2791 = !{!1504, !1813}
+!2792 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2793, file: !2574, line: 1157)
+!2793 = !DISubprogram(name: "lrintl", scope: !2571, file: !2571, line: 314, type: !2794, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2794 = !DISubroutineType(types: !2795)
+!2795 = !{!1504, !1818}
+!2796 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2797, file: !2574, line: 1159)
+!2797 = !DISubprogram(name: "lround", scope: !2571, file: !2571, line: 320, type: !2786, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2798 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2799, file: !2574, line: 1160)
+!2799 = !DISubprogram(name: "lroundf", scope: !2571, file: !2571, line: 320, type: !2790, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2800 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2801, file: !2574, line: 1161)
+!2801 = !DISubprogram(name: "lroundl", scope: !2571, file: !2571, line: 320, type: !2794, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2802 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2803, file: !2574, line: 1163)
+!2803 = !DISubprogram(name: "nan", scope: !2571, file: !2571, line: 201, type: !1663, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2804 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2805, file: !2574, line: 1164)
+!2805 = !DISubprogram(name: "nanf", scope: !2571, file: !2571, line: 201, type: !2806, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2806 = !DISubroutineType(types: !2807)
+!2807 = !{!1813, !1443}
+!2808 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2809, file: !2574, line: 1165)
+!2809 = !DISubprogram(name: "nanl", scope: !2571, file: !2571, line: 201, type: !2810, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2810 = !DISubroutineType(types: !2811)
+!2811 = !{!1818, !1443}
+!2812 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2813, file: !2574, line: 1167)
+!2813 = !DISubprogram(name: "nearbyint", scope: !2571, file: !2571, line: 294, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2814 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2815, file: !2574, line: 1168)
+!2815 = !DISubprogram(name: "nearbyintf", scope: !2571, file: !2571, line: 294, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2816 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2817, file: !2574, line: 1169)
+!2817 = !DISubprogram(name: "nearbyintl", scope: !2571, file: !2571, line: 294, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2818 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2819, file: !2574, line: 1171)
+!2819 = !DISubprogram(name: "nextafter", scope: !2571, file: !2571, line: 259, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2820 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2821, file: !2574, line: 1172)
+!2821 = !DISubprogram(name: "nextafterf", scope: !2571, file: !2571, line: 259, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2822 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2823, file: !2574, line: 1173)
+!2823 = !DISubprogram(name: "nextafterl", scope: !2571, file: !2571, line: 259, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2824 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2825, file: !2574, line: 1175)
+!2825 = !DISubprogram(name: "nexttoward", scope: !2571, file: !2571, line: 261, type: !2826, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2826 = !DISubroutineType(types: !2827)
+!2827 = !{!1665, !1665, !1818}
+!2828 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2829, file: !2574, line: 1176)
+!2829 = !DISubprogram(name: "nexttowardf", scope: !2571, file: !2571, line: 261, type: !2830, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2830 = !DISubroutineType(types: !2831)
+!2831 = !{!1813, !1813, !1818}
+!2832 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2833, file: !2574, line: 1177)
+!2833 = !DISubprogram(name: "nexttowardl", scope: !2571, file: !2571, line: 261, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2834 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2835, file: !2574, line: 1179)
+!2835 = !DISubprogram(name: "remainder", scope: !2571, file: !2571, line: 272, type: !2581, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2836 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2837, file: !2574, line: 1180)
+!2837 = !DISubprogram(name: "remainderf", scope: !2571, file: !2571, line: 272, type: !2664, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2838 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2839, file: !2574, line: 1181)
+!2839 = !DISubprogram(name: "remainderl", scope: !2571, file: !2571, line: 272, type: !2668, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2840 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2841, file: !2574, line: 1183)
+!2841 = !DISubprogram(name: "remquo", scope: !2571, file: !2571, line: 307, type: !2842, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2842 = !DISubroutineType(types: !2843)
+!2843 = !{!1665, !1665, !1665, !2601}
+!2844 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2845, file: !2574, line: 1184)
+!2845 = !DISubprogram(name: "remquof", scope: !2571, file: !2571, line: 307, type: !2846, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2846 = !DISubroutineType(types: !2847)
+!2847 = !{!1813, !1813, !1813, !2601}
+!2848 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2849, file: !2574, line: 1185)
+!2849 = !DISubprogram(name: "remquol", scope: !2571, file: !2571, line: 307, type: !2850, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2850 = !DISubroutineType(types: !2851)
+!2851 = !{!1818, !1818, !1818, !2601}
+!2852 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2853, file: !2574, line: 1187)
+!2853 = !DISubprogram(name: "rint", scope: !2571, file: !2571, line: 256, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2854 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2855, file: !2574, line: 1188)
+!2855 = !DISubprogram(name: "rintf", scope: !2571, file: !2571, line: 256, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2856 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2857, file: !2574, line: 1189)
+!2857 = !DISubprogram(name: "rintl", scope: !2571, file: !2571, line: 256, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2858 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2859, file: !2574, line: 1191)
+!2859 = !DISubprogram(name: "round", scope: !2571, file: !2571, line: 298, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2860 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2861, file: !2574, line: 1192)
+!2861 = !DISubprogram(name: "roundf", scope: !2571, file: !2571, line: 298, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2862 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2863, file: !2574, line: 1193)
+!2863 = !DISubprogram(name: "roundl", scope: !2571, file: !2571, line: 298, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2864 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2865, file: !2574, line: 1195)
+!2865 = !DISubprogram(name: "scalbln", scope: !2571, file: !2571, line: 290, type: !2866, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2866 = !DISubroutineType(types: !2867)
+!2867 = !{!1665, !1665, !1504}
+!2868 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2869, file: !2574, line: 1196)
+!2869 = !DISubprogram(name: "scalblnf", scope: !2571, file: !2571, line: 290, type: !2870, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2870 = !DISubroutineType(types: !2871)
+!2871 = !{!1813, !1813, !1504}
+!2872 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2873, file: !2574, line: 1197)
+!2873 = !DISubprogram(name: "scalblnl", scope: !2571, file: !2571, line: 290, type: !2874, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2874 = !DISubroutineType(types: !2875)
+!2875 = !{!1818, !1818, !1504}
+!2876 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2877, file: !2574, line: 1199)
+!2877 = !DISubprogram(name: "scalbn", scope: !2571, file: !2571, line: 276, type: !2604, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2878 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2879, file: !2574, line: 1200)
+!2879 = !DISubprogram(name: "scalbnf", scope: !2571, file: !2571, line: 276, type: !2880, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2880 = !DISubroutineType(types: !2881)
+!2881 = !{!1813, !1813, !93}
+!2882 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2883, file: !2574, line: 1201)
+!2883 = !DISubprogram(name: "scalbnl", scope: !2571, file: !2571, line: 276, type: !2884, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2884 = !DISubroutineType(types: !2885)
+!2885 = !{!1818, !1818, !93}
+!2886 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2887, file: !2574, line: 1203)
+!2887 = !DISubprogram(name: "tgamma", scope: !2571, file: !2571, line: 235, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2888 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2889, file: !2574, line: 1204)
+!2889 = !DISubprogram(name: "tgammaf", scope: !2571, file: !2571, line: 235, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2890 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2891, file: !2574, line: 1205)
+!2891 = !DISubprogram(name: "tgammal", scope: !2571, file: !2571, line: 235, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2892 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2893, file: !2574, line: 1207)
+!2893 = !DISubprogram(name: "trunc", scope: !2571, file: !2571, line: 302, type: !2572, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2894 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2895, file: !2574, line: 1208)
+!2895 = !DISubprogram(name: "truncf", scope: !2571, file: !2571, line: 302, type: !2636, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2896 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !13, entity: !2897, file: !2574, line: 1209)
+!2897 = !DISubprogram(name: "truncl", scope: !2571, file: !2571, line: 302, type: !2640, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: true)
+!2898 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !2899, entity: !2900, file: !2902, line: 178)
+!2899 = !DINamespace(name: "JS", scope: null)
+!2900 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Ok", scope: !20, file: !2901, line: 26, size: 8, flags: DIFlagTypePassByValue, elements: !114, identifier: "_ZTSN7mozilla2OkE")
+!2901 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/Result.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2902 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/js/Result.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2903 = !{i32 2, !"Dwarf Version", i32 4}
+!2904 = !{i32 2, !"Debug Info Version", i32 3}
+!2905 = !{i32 1, !"wchar_size", i32 4}
+!2906 = !{i32 7, !"PIC Level", i32 2}
+!2907 = !{!"clang version 7.0.0 (tags/RELEASE_700/final)"}
+!2908 = distinct !DISubprogram(name: "GetLSBRelease", linkageName: "_ZN7mozilla6widget3lsb13GetLSBReleaseER12nsTSubstringIcES4_S4_S4_", scope: !1570, file: !1, line: 19, type: !2909, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2914)
+!2909 = !DISubroutineType(types: !2910)
+!2910 = !{!117, !2911, !2911, !2911, !2911}
+!2911 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !2912, size: 64)
+!2912 = !DIDerivedType(tag: DW_TAG_typedef, name: "nsACString", file: !2913, line: 75, baseType: !39)
+!2913 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/nsStringFwd.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!2914 = !{!2915, !2916, !2917, !2918, !2919, !2923, !3145, !3499, !3505, !3506, !3572, !3576, !3577, !3578}
+!2915 = !DILocalVariable(name: "aDistributor", arg: 1, scope: !2908, file: !1, line: 19, type: !2911)
+!2916 = !DILocalVariable(name: "aDescription", arg: 2, scope: !2908, file: !1, line: 19, type: !2911)
+!2917 = !DILocalVariable(name: "aRelease", arg: 3, scope: !2908, file: !1, line: 20, type: !2911)
+!2918 = !DILocalVariable(name: "aCodename", arg: 4, scope: !2908, file: !1, line: 20, type: !2911)
+!2919 = !DILocalVariable(name: "pipefd", scope: !2908, file: !1, line: 23, type: !2920)
+!2920 = !DICompositeType(tag: DW_TAG_array_type, baseType: !93, size: 64, elements: !2921)
+!2921 = !{!2922}
+!2922 = !DISubrange(count: 2)
+!2923 = !DILocalVariable(name: "argv", scope: !2908, file: !1, line: 29, type: !2924)
+!2924 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >", scope: !13, file: !49, line: 339, size: 192, flags: DIFlagTypePassByReference, elements: !2925, templateParams: !1155, identifier: "_ZTSSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE")
+!2925 = !{!2926, !2927, !2931, !2937, !2940, !2946, !2951, !2955, !2958, !2961, !2989, !2990, !2994, !2997, !3000, !3003, !3006, !3011, !3017, !3018, !3019, !3024, !3029, !3030, !3031, !3032, !3033, !3034, !3035, !3038, !3039, !3042, !3043, !3044, !3045, !3048, !3049, !3057, !3064, !3067, !3068, !3069, !3072, !3075, !3076, !3077, !3080, !3083, !3086, !3090, !3091, !3094, !3097, !3100, !3103, !3106, !3109, !3112, !3113, !3114, !3115, !3116, !3119, !3120, !3123, !3124, !3125, !3129, !3133, !3136, !3139, !3142}
+!2926 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !2924, baseType: !990, flags: DIFlagProtected, extraData: i32 0)
+!2927 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 391, type: !2928, isLocal: false, isDefinition: false, scopeLine: 391, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2928 = !DISubroutineType(types: !2929)
+!2929 = !{null, !2930}
+!2930 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2924, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!2931 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 402, type: !2932, isLocal: false, isDefinition: false, scopeLine: 402, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!2932 = !DISubroutineType(types: !2933)
+!2933 = !{null, !2930, !2934}
+!2934 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !2935, size: 64)
+!2935 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2936)
+!2936 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !2924, file: !49, line: 376, baseType: !1011)
+!2937 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 415, type: !2938, isLocal: false, isDefinition: false, scopeLine: 415, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!2938 = !DISubroutineType(types: !2939)
+!2939 = !{null, !2930, !1260, !2934}
+!2940 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 427, type: !2941, isLocal: false, isDefinition: false, scopeLine: 427, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2941 = !DISubroutineType(types: !2942)
+!2942 = !{null, !2930, !1260, !2943, !2934}
+!2943 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !2944, size: 64)
+!2944 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2945)
+!2945 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !2924, file: !49, line: 364, baseType: !31)
+!2946 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 458, type: !2947, isLocal: false, isDefinition: false, scopeLine: 458, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2947 = !DISubroutineType(types: !2948)
+!2948 = !{null, !2930, !2949}
+!2949 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !2950, size: 64)
+!2950 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2924)
+!2951 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 476, type: !2952, isLocal: false, isDefinition: false, scopeLine: 476, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2952 = !DISubroutineType(types: !2953)
+!2953 = !{null, !2930, !2954}
+!2954 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !2924, size: 64)
+!2955 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 480, type: !2956, isLocal: false, isDefinition: false, scopeLine: 480, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2956 = !DISubroutineType(types: !2957)
+!2957 = !{null, !2930, !2949, !2934}
+!2958 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 490, type: !2959, isLocal: false, isDefinition: false, scopeLine: 490, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2959 = !DISubroutineType(types: !2960)
+!2960 = !{null, !2930, !2954, !2934}
+!2961 = !DISubprogram(name: "vector", scope: !2924, file: !49, line: 515, type: !2962, isLocal: false, isDefinition: false, scopeLine: 515, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2962 = !DISubroutineType(types: !2963)
+!2963 = !{null, !2930, !2964, !2934}
+!2964 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "initializer_list<std::__cxx11::basic_string<char> >", scope: !13, file: !1304, line: 47, size: 128, flags: DIFlagTypePassByValue, elements: !2965, templateParams: !2987, identifier: "_ZTSSt16initializer_listINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE")
+!2965 = !{!2966, !2968, !2970, !2975, !2978, !2983, !2986}
+!2966 = !DIDerivedType(tag: DW_TAG_member, name: "_M_array", scope: !2964, file: !1304, line: 58, baseType: !2967, size: 64)
+!2967 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator", scope: !2964, file: !1304, line: 54, baseType: !1038)
+!2968 = !DIDerivedType(tag: DW_TAG_member, name: "_M_len", scope: !2964, file: !1304, line: 59, baseType: !2969, size: 64, offset: 64)
+!2969 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", file: !1304, line: 53, baseType: !175)
+!2970 = !DISubprogram(name: "initializer_list", scope: !2964, file: !1304, line: 62, type: !2971, isLocal: false, isDefinition: false, scopeLine: 62, flags: DIFlagPrototyped, isOptimized: true)
+!2971 = !DISubroutineType(types: !2972)
+!2972 = !{null, !2973, !2974, !2969}
+!2973 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2964, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!2974 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_iterator", scope: !2964, file: !1304, line: 55, baseType: !1038)
+!2975 = !DISubprogram(name: "initializer_list", scope: !2964, file: !1304, line: 66, type: !2976, isLocal: false, isDefinition: false, scopeLine: 66, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2976 = !DISubroutineType(types: !2977)
+!2977 = !{null, !2973}
+!2978 = !DISubprogram(name: "size", linkageName: "_ZNKSt16initializer_listINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE4sizeEv", scope: !2964, file: !1304, line: 71, type: !2979, isLocal: false, isDefinition: false, scopeLine: 71, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2979 = !DISubroutineType(types: !2980)
+!2980 = !{!2969, !2981}
+!2981 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2982, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!2982 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !2964)
+!2983 = !DISubprogram(name: "begin", linkageName: "_ZNKSt16initializer_listINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5beginEv", scope: !2964, file: !1304, line: 75, type: !2984, isLocal: false, isDefinition: false, scopeLine: 75, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2984 = !DISubroutineType(types: !2985)
+!2985 = !{!2974, !2981}
+!2986 = !DISubprogram(name: "end", linkageName: "_ZNKSt16initializer_listINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE3endEv", scope: !2964, file: !1304, line: 79, type: !2984, isLocal: false, isDefinition: false, scopeLine: 79, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2987 = !{!2988}
+!2988 = !DITemplateTypeParameter(name: "_E", type: !31)
+!2989 = !DISubprogram(name: "~vector", scope: !2924, file: !49, line: 565, type: !2928, isLocal: false, isDefinition: false, scopeLine: 565, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2990 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEaSERKS7_", scope: !2924, file: !49, line: 582, type: !2991, isLocal: false, isDefinition: false, scopeLine: 582, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2991 = !DISubroutineType(types: !2992)
+!2992 = !{!2993, !2930, !2949}
+!2993 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !2924, size: 64)
+!2994 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEaSEOS7_", scope: !2924, file: !49, line: 596, type: !2995, isLocal: false, isDefinition: false, scopeLine: 596, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2995 = !DISubroutineType(types: !2996)
+!2996 = !{!2993, !2930, !2954}
+!2997 = !DISubprogram(name: "operator=", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEaSESt16initializer_listIS5_E", scope: !2924, file: !49, line: 617, type: !2998, isLocal: false, isDefinition: false, scopeLine: 617, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!2998 = !DISubroutineType(types: !2999)
+!2999 = !{!2993, !2930, !2964}
+!3000 = !DISubprogram(name: "assign", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6assignEmRKS5_", scope: !2924, file: !49, line: 636, type: !3001, isLocal: false, isDefinition: false, scopeLine: 636, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3001 = !DISubroutineType(types: !3002)
+!3002 = !{null, !2930, !1260, !2943}
+!3003 = !DISubprogram(name: "assign", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6assignESt16initializer_listIS5_E", scope: !2924, file: !49, line: 681, type: !3004, isLocal: false, isDefinition: false, scopeLine: 681, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3004 = !DISubroutineType(types: !3005)
+!3005 = !{null, !2930, !2964}
+!3006 = !DISubprogram(name: "begin", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5beginEv", scope: !2924, file: !49, line: 698, type: !3007, isLocal: false, isDefinition: false, scopeLine: 698, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3007 = !DISubroutineType(types: !3008)
+!3008 = !{!3009, !2930}
+!3009 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator", scope: !2924, file: !49, line: 369, baseType: !3010)
+!3010 = !DICompositeType(tag: DW_TAG_class_type, name: "__normal_iterator<std::__cxx11::basic_string<char> *, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > >", scope: !5, file: !879, line: 764, flags: DIFlagFwdDecl, identifier: "_ZTSN9__gnu_cxx17__normal_iteratorIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS6_SaIS6_EEEE")
+!3011 = !DISubprogram(name: "begin", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5beginEv", scope: !2924, file: !49, line: 707, type: !3012, isLocal: false, isDefinition: false, scopeLine: 707, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3012 = !DISubroutineType(types: !3013)
+!3013 = !{!3014, !3016}
+!3014 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_iterator", scope: !2924, file: !49, line: 371, baseType: !3015)
+!3015 = !DICompositeType(tag: DW_TAG_class_type, name: "__normal_iterator<const std::__cxx11::basic_string<char> *, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > >", scope: !5, file: !879, line: 764, flags: DIFlagFwdDecl, identifier: "_ZTSN9__gnu_cxx17__normal_iteratorIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS6_SaIS6_EEEE")
+!3016 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2950, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3017 = !DISubprogram(name: "end", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE3endEv", scope: !2924, file: !49, line: 716, type: !3007, isLocal: false, isDefinition: false, scopeLine: 716, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3018 = !DISubprogram(name: "end", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE3endEv", scope: !2924, file: !49, line: 725, type: !3012, isLocal: false, isDefinition: false, scopeLine: 725, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3019 = !DISubprogram(name: "rbegin", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6rbeginEv", scope: !2924, file: !49, line: 734, type: !3020, isLocal: false, isDefinition: false, scopeLine: 734, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3020 = !DISubroutineType(types: !3021)
+!3021 = !{!3022, !2930}
+!3022 = !DIDerivedType(tag: DW_TAG_typedef, name: "reverse_iterator", scope: !2924, file: !49, line: 373, baseType: !3023)
+!3023 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char> *, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS7_SaIS7_EEEEE")
+!3024 = !DISubprogram(name: "rbegin", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6rbeginEv", scope: !2924, file: !49, line: 743, type: !3025, isLocal: false, isDefinition: false, scopeLine: 743, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3025 = !DISubroutineType(types: !3026)
+!3026 = !{!3027, !3016}
+!3027 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reverse_iterator", scope: !2924, file: !49, line: 372, baseType: !3028)
+!3028 = !DICompositeType(tag: DW_TAG_class_type, name: "reverse_iterator<__gnu_cxx::__normal_iterator<const std::__cxx11::basic_string<char> *, std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > > > >", scope: !13, file: !879, line: 101, flags: DIFlagFwdDecl, identifier: "_ZTSSt16reverse_iteratorIN9__gnu_cxx17__normal_iteratorIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt6vectorIS7_SaIS7_EEEEE")
+!3029 = !DISubprogram(name: "rend", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4rendEv", scope: !2924, file: !49, line: 752, type: !3020, isLocal: false, isDefinition: false, scopeLine: 752, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3030 = !DISubprogram(name: "rend", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4rendEv", scope: !2924, file: !49, line: 761, type: !3025, isLocal: false, isDefinition: false, scopeLine: 761, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3031 = !DISubprogram(name: "cbegin", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6cbeginEv", scope: !2924, file: !49, line: 771, type: !3012, isLocal: false, isDefinition: false, scopeLine: 771, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3032 = !DISubprogram(name: "cend", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4cendEv", scope: !2924, file: !49, line: 780, type: !3012, isLocal: false, isDefinition: false, scopeLine: 780, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3033 = !DISubprogram(name: "crbegin", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE7crbeginEv", scope: !2924, file: !49, line: 789, type: !3025, isLocal: false, isDefinition: false, scopeLine: 789, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3034 = !DISubprogram(name: "crend", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5crendEv", scope: !2924, file: !49, line: 798, type: !3025, isLocal: false, isDefinition: false, scopeLine: 798, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3035 = !DISubprogram(name: "size", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4sizeEv", scope: !2924, file: !49, line: 805, type: !3036, isLocal: false, isDefinition: false, scopeLine: 805, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3036 = !DISubroutineType(types: !3037)
+!3037 = !{!1260, !3016}
+!3038 = !DISubprogram(name: "max_size", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE8max_sizeEv", scope: !2924, file: !49, line: 810, type: !3036, isLocal: false, isDefinition: false, scopeLine: 810, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3039 = !DISubprogram(name: "resize", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6resizeEm", scope: !2924, file: !49, line: 824, type: !3040, isLocal: false, isDefinition: false, scopeLine: 824, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3040 = !DISubroutineType(types: !3041)
+!3041 = !{null, !2930, !1260}
+!3042 = !DISubprogram(name: "resize", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6resizeEmRKS5_", scope: !2924, file: !49, line: 844, type: !3001, isLocal: false, isDefinition: false, scopeLine: 844, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3043 = !DISubprogram(name: "shrink_to_fit", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE13shrink_to_fitEv", scope: !2924, file: !49, line: 876, type: !2928, isLocal: false, isDefinition: false, scopeLine: 876, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3044 = !DISubprogram(name: "capacity", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE8capacityEv", scope: !2924, file: !49, line: 885, type: !3036, isLocal: false, isDefinition: false, scopeLine: 885, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3045 = !DISubprogram(name: "empty", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5emptyEv", scope: !2924, file: !49, line: 894, type: !3046, isLocal: false, isDefinition: false, scopeLine: 894, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3046 = !DISubroutineType(types: !3047)
+!3047 = !{!117, !3016}
+!3048 = !DISubprogram(name: "reserve", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE7reserveEm", scope: !2924, file: !49, line: 915, type: !3040, isLocal: false, isDefinition: false, scopeLine: 915, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3049 = !DISubprogram(name: "operator[]", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEixEm", scope: !2924, file: !49, line: 930, type: !3050, isLocal: false, isDefinition: false, scopeLine: 930, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3050 = !DISubroutineType(types: !3051)
+!3051 = !{!3052, !2930, !1260}
+!3052 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !2924, file: !49, line: 367, baseType: !3053)
+!3053 = !DIDerivedType(tag: DW_TAG_typedef, name: "reference", scope: !999, file: !59, line: 64, baseType: !3054)
+!3054 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3055, size: 64)
+!3055 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !999, file: !59, line: 58, baseType: !3056)
+!3056 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !1002, file: !64, line: 389, baseType: !31)
+!3057 = !DISubprogram(name: "operator[]", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEixEm", scope: !2924, file: !49, line: 948, type: !3058, isLocal: false, isDefinition: false, scopeLine: 948, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3058 = !DISubroutineType(types: !3059)
+!3059 = !{!3060, !3016, !1260}
+!3060 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !2924, file: !49, line: 368, baseType: !3061)
+!3061 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reference", scope: !999, file: !59, line: 65, baseType: !3062)
+!3062 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3063, size: 64)
+!3063 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3055)
+!3064 = !DISubprogram(name: "_M_range_check", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_range_checkEm", scope: !2924, file: !49, line: 957, type: !3065, isLocal: false, isDefinition: false, scopeLine: 957, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3065 = !DISubroutineType(types: !3066)
+!3066 = !{null, !3016, !1260}
+!3067 = !DISubprogram(name: "at", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE2atEm", scope: !2924, file: !49, line: 979, type: !3050, isLocal: false, isDefinition: false, scopeLine: 979, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3068 = !DISubprogram(name: "at", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE2atEm", scope: !2924, file: !49, line: 997, type: !3058, isLocal: false, isDefinition: false, scopeLine: 997, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3069 = !DISubprogram(name: "front", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5frontEv", scope: !2924, file: !49, line: 1008, type: !3070, isLocal: false, isDefinition: false, scopeLine: 1008, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3070 = !DISubroutineType(types: !3071)
+!3071 = !{!3052, !2930}
+!3072 = !DISubprogram(name: "front", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5frontEv", scope: !2924, file: !49, line: 1019, type: !3073, isLocal: false, isDefinition: false, scopeLine: 1019, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3073 = !DISubroutineType(types: !3074)
+!3074 = !{!3060, !3016}
+!3075 = !DISubprogram(name: "back", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4backEv", scope: !2924, file: !49, line: 1030, type: !3070, isLocal: false, isDefinition: false, scopeLine: 1030, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3076 = !DISubprogram(name: "back", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4backEv", scope: !2924, file: !49, line: 1041, type: !3073, isLocal: false, isDefinition: false, scopeLine: 1041, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3077 = !DISubprogram(name: "data", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4dataEv", scope: !2924, file: !49, line: 1055, type: !3078, isLocal: false, isDefinition: false, scopeLine: 1055, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3078 = !DISubroutineType(types: !3079)
+!3079 = !{!1008, !2930}
+!3080 = !DISubprogram(name: "data", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4dataEv", scope: !2924, file: !49, line: 1059, type: !3081, isLocal: false, isDefinition: false, scopeLine: 1059, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3081 = !DISubroutineType(types: !3082)
+!3082 = !{!1038, !3016}
+!3083 = !DISubprogram(name: "push_back", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE9push_backERKS5_", scope: !2924, file: !49, line: 1074, type: !3084, isLocal: false, isDefinition: false, scopeLine: 1074, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3084 = !DISubroutineType(types: !3085)
+!3085 = !{null, !2930, !2943}
+!3086 = !DISubprogram(name: "push_back", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE9push_backEOS5_", scope: !2924, file: !49, line: 1090, type: !3087, isLocal: false, isDefinition: false, scopeLine: 1090, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3087 = !DISubroutineType(types: !3088)
+!3088 = !{null, !2930, !3089}
+!3089 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !2945, size: 64)
+!3090 = !DISubprogram(name: "pop_back", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE8pop_backEv", scope: !2924, file: !49, line: 1112, type: !2928, isLocal: false, isDefinition: false, scopeLine: 1112, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3091 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EERSA_", scope: !2924, file: !49, line: 1150, type: !3092, isLocal: false, isDefinition: false, scopeLine: 1150, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3092 = !DISubroutineType(types: !3093)
+!3093 = !{!3009, !2930, !3014, !2943}
+!3094 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EEOS5_", scope: !2924, file: !49, line: 1180, type: !3095, isLocal: false, isDefinition: false, scopeLine: 1180, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3095 = !DISubroutineType(types: !3096)
+!3096 = !{!3009, !2930, !3014, !3089}
+!3097 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EESt16initializer_listIS5_E", scope: !2924, file: !49, line: 1197, type: !3098, isLocal: false, isDefinition: false, scopeLine: 1197, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3098 = !DISubroutineType(types: !3099)
+!3099 = !{!3009, !2930, !3014, !2964}
+!3100 = !DISubprogram(name: "insert", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE6insertEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EEmRSA_", scope: !2924, file: !49, line: 1222, type: !3101, isLocal: false, isDefinition: false, scopeLine: 1222, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3101 = !DISubroutineType(types: !3102)
+!3102 = !{!3009, !2930, !3014, !1260, !2943}
+!3103 = !DISubprogram(name: "erase", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5eraseEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EE", scope: !2924, file: !49, line: 1317, type: !3104, isLocal: false, isDefinition: false, scopeLine: 1317, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3104 = !DISubroutineType(types: !3105)
+!3105 = !{!3009, !2930, !3014}
+!3106 = !DISubprogram(name: "erase", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5eraseEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EESC_", scope: !2924, file: !49, line: 1344, type: !3107, isLocal: false, isDefinition: false, scopeLine: 1344, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3107 = !DISubroutineType(types: !3108)
+!3108 = !{!3009, !2930, !3014, !3014}
+!3109 = !DISubprogram(name: "swap", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE4swapERS7_", scope: !2924, file: !49, line: 1367, type: !3110, isLocal: false, isDefinition: false, scopeLine: 1367, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3110 = !DISubroutineType(types: !3111)
+!3111 = !{null, !2930, !2993}
+!3112 = !DISubprogram(name: "clear", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE5clearEv", scope: !2924, file: !49, line: 1385, type: !2928, isLocal: false, isDefinition: false, scopeLine: 1385, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3113 = !DISubprogram(name: "_M_fill_initialize", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE18_M_fill_initializeEmRKS5_", scope: !2924, file: !49, line: 1477, type: !3001, isLocal: false, isDefinition: false, scopeLine: 1477, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3114 = !DISubprogram(name: "_M_default_initialize", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE21_M_default_initializeEm", scope: !2924, file: !49, line: 1487, type: !3040, isLocal: false, isDefinition: false, scopeLine: 1487, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3115 = !DISubprogram(name: "_M_fill_assign", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_fill_assignEmRKS5_", scope: !2924, file: !49, line: 1529, type: !3001, isLocal: false, isDefinition: false, scopeLine: 1529, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3116 = !DISubprogram(name: "_M_fill_insert", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_fill_insertEN9__gnu_cxx17__normal_iteratorIPS5_S7_EEmRKS5_", scope: !2924, file: !49, line: 1568, type: !3117, isLocal: false, isDefinition: false, scopeLine: 1568, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3117 = !DISubroutineType(types: !3118)
+!3118 = !{null, !2930, !3009, !1260, !2943}
+!3119 = !DISubprogram(name: "_M_default_append", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE17_M_default_appendEm", scope: !2924, file: !49, line: 1573, type: !3040, isLocal: false, isDefinition: false, scopeLine: 1573, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3120 = !DISubprogram(name: "_M_shrink_to_fit", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE16_M_shrink_to_fitEv", scope: !2924, file: !49, line: 1576, type: !3121, isLocal: false, isDefinition: false, scopeLine: 1576, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3121 = !DISubroutineType(types: !3122)
+!3122 = !{!117, !2930}
+!3123 = !DISubprogram(name: "_M_insert_rval", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_insert_rvalEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EEOS5_", scope: !2924, file: !49, line: 1625, type: !3095, isLocal: false, isDefinition: false, scopeLine: 1625, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3124 = !DISubprogram(name: "_M_emplace_aux", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_emplace_auxEN9__gnu_cxx17__normal_iteratorIPKS5_S7_EEOS5_", scope: !2924, file: !49, line: 1634, type: !3095, isLocal: false, isDefinition: false, scopeLine: 1634, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3125 = !DISubprogram(name: "_M_check_len", linkageName: "_ZNKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12_M_check_lenEmPKc", scope: !2924, file: !49, line: 1640, type: !3126, isLocal: false, isDefinition: false, scopeLine: 1640, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3126 = !DISubroutineType(types: !3127)
+!3127 = !{!3128, !3016, !1260, !1443}
+!3128 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !2924, file: !49, line: 374, baseType: !175)
+!3129 = !DISubprogram(name: "_M_erase_at_end", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE15_M_erase_at_endEPS5_", scope: !2924, file: !49, line: 1654, type: !3130, isLocal: false, isDefinition: false, scopeLine: 1654, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3130 = !DISubroutineType(types: !3131)
+!3131 = !{null, !2930, !3132}
+!3132 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !2924, file: !49, line: 365, baseType: !997)
+!3133 = !DISubprogram(name: "_M_erase", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS5_S7_EE", scope: !2924, file: !49, line: 1666, type: !3134, isLocal: false, isDefinition: false, scopeLine: 1666, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3134 = !DISubroutineType(types: !3135)
+!3135 = !{!3009, !2930, !3009}
+!3136 = !DISubprogram(name: "_M_erase", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE8_M_eraseEN9__gnu_cxx17__normal_iteratorIPS5_S7_EESB_", scope: !2924, file: !49, line: 1669, type: !3137, isLocal: false, isDefinition: false, scopeLine: 1669, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3137 = !DISubroutineType(types: !3138)
+!3138 = !{!3009, !2930, !3009, !3009}
+!3139 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_move_assignEOS7_St17integral_constantIbLb1EE", scope: !2924, file: !49, line: 1677, type: !3140, isLocal: false, isDefinition: false, scopeLine: 1677, flags: DIFlagPrototyped, isOptimized: true)
+!3140 = !DISubroutineType(types: !3141)
+!3141 = !{null, !2930, !2954, !950}
+!3142 = !DISubprogram(name: "_M_move_assign", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE14_M_move_assignEOS7_St17integral_constantIbLb0EE", scope: !2924, file: !49, line: 1688, type: !3143, isLocal: false, isDefinition: false, scopeLine: 1688, flags: DIFlagPrototyped, isOptimized: true)
+!3143 = !DISubroutineType(types: !3144)
+!3144 = !{null, !2930, !2954, !968}
+!3145 = !DILocalVariable(name: "options", scope: !2908, file: !1, line: 31, type: !3146)
+!3146 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "LaunchOptions", scope: !3148, file: !3147, line: 96, size: 704, flags: DIFlagTypePassByReference, elements: !3149, identifier: "_ZTSN4base13LaunchOptionsE")
+!3147 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/ipc/chromium/src/base/process_util.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3148 = !DINamespace(name: "base", scope: null)
+!3149 = !{!3150, !3151, !3322, !3324}
+!3150 = !DIDerivedType(tag: DW_TAG_member, name: "wait", scope: !3146, file: !3147, line: 99, baseType: !117, size: 8)
+!3151 = !DIDerivedType(tag: DW_TAG_member, name: "env_map", scope: !3146, file: !3147, line: 111, baseType: !3152, size: 384, offset: 64)
+!3152 = !DIDerivedType(tag: DW_TAG_typedef, name: "environment_map", scope: !3148, file: !3147, line: 93, baseType: !3153)
+!3153 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > >", scope: !13, file: !3154, line: 100, size: 384, flags: DIFlagTypePassByReference, elements: !3155, templateParams: !3321, identifier: "_ZTSSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE")
+!3154 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_map.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3155 = !{!3156, !3158, !3162, !3168, !3173, !3177, !3181, !3184, !3187, !3190, !3193, !3194, !3198, !3201, !3204, !3208, !3212, !3216, !3217, !3218, !3222, !3226, !3227, !3228, !3229, !3230, !3231, !3232, !3235, !3239, !3240, !3248, !3252, !3253, !3258, !3265, !3269, !3272, !3275, !3278, !3281, !3284, !3287, !3290, !3293, !3294, !3298, !3302, !3305, !3308, !3311, !3312, !3313, !3314, !3315, !3318}
+!3156 = !DIDerivedType(tag: DW_TAG_member, name: "_M_t", scope: !3153, file: !3154, line: 151, baseType: !3157, size: 384)
+!3157 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Rep_type", scope: !3153, file: !3154, line: 148, baseType: !303)
+!3158 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 183, type: !3159, isLocal: false, isDefinition: false, scopeLine: 183, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3159 = !DISubroutineType(types: !3160)
+!3160 = !{null, !3161}
+!3161 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3153, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3162 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 192, type: !3163, isLocal: false, isDefinition: false, scopeLine: 192, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3163 = !DISubroutineType(types: !3164)
+!3164 = !{null, !3161, !610, !3165}
+!3165 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3166, size: 64)
+!3166 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3167)
+!3167 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !3153, file: !3154, line: 107, baseType: !381)
+!3168 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 205, type: !3169, isLocal: false, isDefinition: false, scopeLine: 205, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3169 = !DISubroutineType(types: !3170)
+!3170 = !{null, !3161, !3171}
+!3171 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3172, size: 64)
+!3172 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3153)
+!3173 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 213, type: !3174, isLocal: false, isDefinition: false, scopeLine: 213, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3174 = !DISubroutineType(types: !3175)
+!3175 = !{null, !3161, !3176}
+!3176 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3153, size: 64)
+!3177 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 226, type: !3178, isLocal: false, isDefinition: false, scopeLine: 226, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3178 = !DISubroutineType(types: !3179)
+!3179 = !{null, !3161, !3180, !610, !3165}
+!3180 = !DICompositeType(tag: DW_TAG_class_type, name: "initializer_list<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", scope: !13, file: !1304, line: 47, flags: DIFlagFwdDecl, identifier: "_ZTSSt16initializer_listISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE")
+!3181 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 234, type: !3182, isLocal: false, isDefinition: false, scopeLine: 234, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3182 = !DISubroutineType(types: !3183)
+!3183 = !{null, !3161, !3165}
+!3184 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 238, type: !3185, isLocal: false, isDefinition: false, scopeLine: 238, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3185 = !DISubroutineType(types: !3186)
+!3186 = !{null, !3161, !3171, !3165}
+!3187 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 242, type: !3188, isLocal: false, isDefinition: false, scopeLine: 242, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3188 = !DISubroutineType(types: !3189)
+!3189 = !{null, !3161, !3176, !3165}
+!3190 = !DISubprogram(name: "map", scope: !3153, file: !3154, line: 248, type: !3191, isLocal: false, isDefinition: false, scopeLine: 248, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3191 = !DISubroutineType(types: !3192)
+!3192 = !{null, !3161, !3180, !3165}
+!3193 = !DISubprogram(name: "~map", scope: !3153, file: !3154, line: 300, type: !3159, isLocal: false, isDefinition: false, scopeLine: 300, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3194 = !DISubprogram(name: "operator=", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEaSERKSC_", scope: !3153, file: !3154, line: 317, type: !3195, isLocal: false, isDefinition: false, scopeLine: 317, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3195 = !DISubroutineType(types: !3196)
+!3196 = !{!3197, !3161, !3171}
+!3197 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3153, size: 64)
+!3198 = !DISubprogram(name: "operator=", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEaSEOSC_", scope: !3153, file: !3154, line: 321, type: !3199, isLocal: false, isDefinition: false, scopeLine: 321, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3199 = !DISubroutineType(types: !3200)
+!3200 = !{!3197, !3161, !3176}
+!3201 = !DISubprogram(name: "operator=", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEaSESt16initializer_listISA_E", scope: !3153, file: !3154, line: 335, type: !3202, isLocal: false, isDefinition: false, scopeLine: 335, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3202 = !DISubroutineType(types: !3203)
+!3203 = !{!3197, !3161, !3180}
+!3204 = !DISubprogram(name: "get_allocator", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE13get_allocatorEv", scope: !3153, file: !3154, line: 344, type: !3205, isLocal: false, isDefinition: false, scopeLine: 344, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3205 = !DISubroutineType(types: !3206)
+!3206 = !{!3167, !3207}
+!3207 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3172, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3208 = !DISubprogram(name: "begin", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5beginEv", scope: !3153, file: !3154, line: 354, type: !3209, isLocal: false, isDefinition: false, scopeLine: 354, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3209 = !DISubroutineType(types: !3210)
+!3210 = !{!3211, !3161}
+!3211 = !DIDerivedType(tag: DW_TAG_typedef, name: "iterator", scope: !3153, file: !3154, line: 162, baseType: !810)
+!3212 = !DISubprogram(name: "begin", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5beginEv", scope: !3153, file: !3154, line: 363, type: !3213, isLocal: false, isDefinition: false, scopeLine: 363, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3213 = !DISubroutineType(types: !3214)
+!3214 = !{!3215, !3207}
+!3215 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_iterator", scope: !3153, file: !3154, line: 163, baseType: !804)
+!3216 = !DISubprogram(name: "end", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE3endEv", scope: !3153, file: !3154, line: 372, type: !3209, isLocal: false, isDefinition: false, scopeLine: 372, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3217 = !DISubprogram(name: "end", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE3endEv", scope: !3153, file: !3154, line: 381, type: !3213, isLocal: false, isDefinition: false, scopeLine: 381, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3218 = !DISubprogram(name: "rbegin", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6rbeginEv", scope: !3153, file: !3154, line: 390, type: !3219, isLocal: false, isDefinition: false, scopeLine: 390, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3219 = !DISubroutineType(types: !3220)
+!3220 = !{!3221, !3161}
+!3221 = !DIDerivedType(tag: DW_TAG_typedef, name: "reverse_iterator", scope: !3153, file: !3154, line: 166, baseType: !877)
+!3222 = !DISubprogram(name: "rbegin", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6rbeginEv", scope: !3153, file: !3154, line: 399, type: !3223, isLocal: false, isDefinition: false, scopeLine: 399, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3223 = !DISubroutineType(types: !3224)
+!3224 = !{!3225, !3207}
+!3225 = !DIDerivedType(tag: DW_TAG_typedef, name: "const_reverse_iterator", scope: !3153, file: !3154, line: 167, baseType: !883)
+!3226 = !DISubprogram(name: "rend", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4rendEv", scope: !3153, file: !3154, line: 408, type: !3219, isLocal: false, isDefinition: false, scopeLine: 408, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3227 = !DISubprogram(name: "rend", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4rendEv", scope: !3153, file: !3154, line: 417, type: !3223, isLocal: false, isDefinition: false, scopeLine: 417, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3228 = !DISubprogram(name: "cbegin", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6cbeginEv", scope: !3153, file: !3154, line: 427, type: !3213, isLocal: false, isDefinition: false, scopeLine: 427, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3229 = !DISubprogram(name: "cend", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4cendEv", scope: !3153, file: !3154, line: 436, type: !3213, isLocal: false, isDefinition: false, scopeLine: 436, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3230 = !DISubprogram(name: "crbegin", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE7crbeginEv", scope: !3153, file: !3154, line: 445, type: !3223, isLocal: false, isDefinition: false, scopeLine: 445, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3231 = !DISubprogram(name: "crend", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5crendEv", scope: !3153, file: !3154, line: 454, type: !3223, isLocal: false, isDefinition: false, scopeLine: 454, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3232 = !DISubprogram(name: "empty", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5emptyEv", scope: !3153, file: !3154, line: 463, type: !3233, isLocal: false, isDefinition: false, scopeLine: 463, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3233 = !DISubroutineType(types: !3234)
+!3234 = !{!117, !3207}
+!3235 = !DISubprogram(name: "size", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4sizeEv", scope: !3153, file: !3154, line: 468, type: !3236, isLocal: false, isDefinition: false, scopeLine: 468, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3236 = !DISubroutineType(types: !3237)
+!3237 = !{!3238, !3207}
+!3238 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !3153, file: !3154, line: 164, baseType: !913)
+!3239 = !DISubprogram(name: "max_size", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE8max_sizeEv", scope: !3153, file: !3154, line: 473, type: !3236, isLocal: false, isDefinition: false, scopeLine: 473, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3240 = !DISubprogram(name: "operator[]", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEixERS9_", scope: !3153, file: !3154, line: 490, type: !3241, isLocal: false, isDefinition: false, scopeLine: 490, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3241 = !DISubroutineType(types: !3242)
+!3242 = !{!3243, !3161, !3245}
+!3243 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3244, size: 64)
+!3244 = !DIDerivedType(tag: DW_TAG_typedef, name: "mapped_type", scope: !3153, file: !3154, line: 104, baseType: !31)
+!3245 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3246, size: 64)
+!3246 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3247)
+!3247 = !DIDerivedType(tag: DW_TAG_typedef, name: "key_type", scope: !3153, file: !3154, line: 103, baseType: !31)
+!3248 = !DISubprogram(name: "operator[]", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEixEOS5_", scope: !3153, file: !3154, line: 510, type: !3249, isLocal: false, isDefinition: false, scopeLine: 510, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3249 = !DISubroutineType(types: !3250)
+!3250 = !{!3243, !3161, !3251}
+!3251 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3247, size: 64)
+!3252 = !DISubprogram(name: "at", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE2atERS9_", scope: !3153, file: !3154, line: 535, type: !3241, isLocal: false, isDefinition: false, scopeLine: 535, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3253 = !DISubprogram(name: "at", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE2atERS9_", scope: !3153, file: !3154, line: 544, type: !3254, isLocal: false, isDefinition: false, scopeLine: 544, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3254 = !DISubroutineType(types: !3255)
+!3255 = !{!3256, !3207, !3245}
+!3256 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3257, size: 64)
+!3257 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3244)
+!3258 = !DISubprogram(name: "insert", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6insertERKSA_", scope: !3153, file: !3154, line: 801, type: !3259, isLocal: false, isDefinition: false, scopeLine: 801, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3259 = !DISubroutineType(types: !3260)
+!3260 = !{!3261, !3161, !3262}
+!3261 = !DICompositeType(tag: DW_TAG_structure_type, name: "pair<std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >, bool>", scope: !13, file: !72, line: 208, flags: DIFlagFwdDecl, identifier: "_ZTSSt4pairISt17_Rb_tree_iteratorIS_IKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EEbE")
+!3262 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3263, size: 64)
+!3263 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3264)
+!3264 = !DIDerivedType(tag: DW_TAG_typedef, name: "value_type", scope: !3153, file: !3154, line: 105, baseType: !322)
+!3265 = !DISubprogram(name: "insert", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6insertEOSA_", scope: !3153, file: !3154, line: 808, type: !3266, isLocal: false, isDefinition: false, scopeLine: 808, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3266 = !DISubroutineType(types: !3267)
+!3267 = !{!3261, !3161, !3268}
+!3268 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3264, size: 64)
+!3269 = !DISubprogram(name: "insert", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6insertESt16initializer_listISA_E", scope: !3153, file: !3154, line: 828, type: !3270, isLocal: false, isDefinition: false, scopeLine: 828, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3270 = !DISubroutineType(types: !3271)
+!3271 = !{null, !3161, !3180}
+!3272 = !DISubprogram(name: "insert", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6insertESt23_Rb_tree_const_iteratorISA_ERKSA_", scope: !3153, file: !3154, line: 858, type: !3273, isLocal: false, isDefinition: false, scopeLine: 858, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3273 = !DISubroutineType(types: !3274)
+!3274 = !{!3211, !3161, !3215, !3262}
+!3275 = !DISubprogram(name: "insert", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE6insertESt23_Rb_tree_const_iteratorISA_EOSA_", scope: !3153, file: !3154, line: 868, type: !3276, isLocal: false, isDefinition: false, scopeLine: 868, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3276 = !DISubroutineType(types: !3277)
+!3277 = !{!3211, !3161, !3215, !3268}
+!3278 = !DISubprogram(name: "erase", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5eraseESt23_Rb_tree_const_iteratorISA_E", scope: !3153, file: !3154, line: 1030, type: !3279, isLocal: false, isDefinition: false, scopeLine: 1030, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3279 = !DISubroutineType(types: !3280)
+!3280 = !{!3211, !3161, !3215}
+!3281 = !DISubprogram(name: "erase", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5eraseB5cxx11ESt17_Rb_tree_iteratorISA_E", scope: !3153, file: !3154, line: 1036, type: !3282, isLocal: false, isDefinition: false, scopeLine: 1036, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3282 = !DISubroutineType(types: !3283)
+!3283 = !{!3211, !3161, !3211}
+!3284 = !DISubprogram(name: "erase", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5eraseERS9_", scope: !3153, file: !3154, line: 1067, type: !3285, isLocal: false, isDefinition: false, scopeLine: 1067, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3285 = !DISubroutineType(types: !3286)
+!3286 = !{!3238, !3161, !3245}
+!3287 = !DISubprogram(name: "erase", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5eraseESt23_Rb_tree_const_iteratorISA_ESE_", scope: !3153, file: !3154, line: 1087, type: !3288, isLocal: false, isDefinition: false, scopeLine: 1087, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3288 = !DISubroutineType(types: !3289)
+!3289 = !{!3211, !3161, !3215, !3215}
+!3290 = !DISubprogram(name: "swap", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4swapERSC_", scope: !3153, file: !3154, line: 1121, type: !3291, isLocal: false, isDefinition: false, scopeLine: 1121, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3291 = !DISubroutineType(types: !3292)
+!3292 = !{null, !3161, !3197}
+!3293 = !DISubprogram(name: "clear", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5clearEv", scope: !3153, file: !3154, line: 1132, type: !3159, isLocal: false, isDefinition: false, scopeLine: 1132, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3294 = !DISubprogram(name: "key_comp", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE8key_compEv", scope: !3153, file: !3154, line: 1141, type: !3295, isLocal: false, isDefinition: false, scopeLine: 1141, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3295 = !DISubroutineType(types: !3296)
+!3296 = !{!3297, !3207}
+!3297 = !DIDerivedType(tag: DW_TAG_typedef, name: "key_compare", scope: !3153, file: !3154, line: 106, baseType: !586)
+!3298 = !DISubprogram(name: "value_comp", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE10value_compEv", scope: !3153, file: !3154, line: 1149, type: !3299, isLocal: false, isDefinition: false, scopeLine: 1149, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3299 = !DISubroutineType(types: !3300)
+!3300 = !{!3301, !3207}
+!3301 = !DICompositeType(tag: DW_TAG_class_type, name: "value_compare", scope: !3153, file: !3154, line: 127, flags: DIFlagFwdDecl, identifier: "_ZTSNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE13value_compareE")
+!3302 = !DISubprogram(name: "find", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4findERS9_", scope: !3153, file: !3154, line: 1168, type: !3303, isLocal: false, isDefinition: false, scopeLine: 1168, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3303 = !DISubroutineType(types: !3304)
+!3304 = !{!3211, !3161, !3245}
+!3305 = !DISubprogram(name: "find", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE4findERS9_", scope: !3153, file: !3154, line: 1193, type: !3306, isLocal: false, isDefinition: false, scopeLine: 1193, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3306 = !DISubroutineType(types: !3307)
+!3307 = !{!3215, !3207, !3245}
+!3308 = !DISubprogram(name: "count", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE5countERS9_", scope: !3153, file: !3154, line: 1214, type: !3309, isLocal: false, isDefinition: false, scopeLine: 1214, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3309 = !DISubroutineType(types: !3310)
+!3310 = !{!3238, !3207, !3245}
+!3311 = !DISubprogram(name: "lower_bound", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11lower_boundERS9_", scope: !3153, file: !3154, line: 1238, type: !3303, isLocal: false, isDefinition: false, scopeLine: 1238, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3312 = !DISubprogram(name: "lower_bound", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11lower_boundERS9_", scope: !3153, file: !3154, line: 1263, type: !3306, isLocal: false, isDefinition: false, scopeLine: 1263, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3313 = !DISubprogram(name: "upper_bound", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11upper_boundERS9_", scope: !3153, file: !3154, line: 1283, type: !3303, isLocal: false, isDefinition: false, scopeLine: 1283, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3314 = !DISubprogram(name: "upper_bound", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11upper_boundERS9_", scope: !3153, file: !3154, line: 1303, type: !3306, isLocal: false, isDefinition: false, scopeLine: 1303, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3315 = !DISubprogram(name: "equal_range", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11equal_rangeERS9_", scope: !3153, file: !3154, line: 1332, type: !3316, isLocal: false, isDefinition: false, scopeLine: 1332, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3316 = !DISubroutineType(types: !3317)
+!3317 = !{!938, !3161, !3245}
+!3318 = !DISubprogram(name: "equal_range", linkageName: "_ZNKSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEE11equal_rangeERS9_", scope: !3153, file: !3154, line: 1361, type: !3319, isLocal: false, isDefinition: false, scopeLine: 1361, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3319 = !DISubroutineType(types: !3320)
+!3320 = !{!942, !3207, !3245}
+!3321 = !{!984, !602, !987, !446}
+!3322 = !DIDerivedType(tag: DW_TAG_member, name: "fds_to_remap", scope: !3146, file: !3147, line: 115, baseType: !3323, size: 192, offset: 448)
+!3323 = !DIDerivedType(tag: DW_TAG_typedef, name: "file_handle_mapping_vector", scope: !3148, file: !3147, line: 92, baseType: !1263)
+!3324 = !DIDerivedType(tag: DW_TAG_member, name: "fork_delegate", scope: !3146, file: !3147, line: 126, baseType: !3325, size: 64, offset: 640)
+!3325 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "UniquePtr<base::LaunchOptions::ForkDelegate, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !20, file: !3326, line: 189, size: 64, flags: DIFlagTypePassByReference, elements: !3327, templateParams: !3408, identifier: "_ZTSN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEE")
+!3326 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3327 = !{!3328, !3401, !3415, !3422, !3427, !3432, !3435, !3438, !3447, !3455, !3459, !3462, !3463, !3467, !3470, !3478, !3481, !3484, !3485, !3486, !3487, !3490, !3491, !3494, !3498}
+!3328 = !DIDerivedType(tag: DW_TAG_member, name: "mTuple", scope: !3325, file: !3326, line: 196, baseType: !3329, size: 64)
+!3329 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Pair<base::LaunchOptions::ForkDelegate *, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !20, file: !18, line: 136, size: 64, flags: DIFlagTypePassByReference, elements: !3330, templateParams: !3400, identifier: "_ZTSN7mozilla4PairIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEE")
+!3330 = !{!3331, !3380, !3385, !3390, !3394, !3397}
+!3331 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !3329, baseType: !3332, flags: DIFlagPrivate, extraData: i32 0)
+!3332 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "PairHelper<base::LaunchOptions::ForkDelegate *, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate>, mozilla::detail::AsMember, mozilla::detail::AsBase>", scope: !19, file: !18, line: 61, size: 64, flags: DIFlagTypePassByValue, elements: !3333, templateParams: !3375, identifier: "_ZTSN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EEE")
+!3333 = !{!3334, !3350, !3351, !3356, !3363, !3367, !3371}
+!3334 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !3332, baseType: !3335, flags: DIFlagPrivate, extraData: i32 0)
+!3335 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "DefaultDelete<base::LaunchOptions::ForkDelegate>", scope: !20, file: !3326, line: 474, size: 8, flags: DIFlagTypePassByValue, elements: !3336, templateParams: !3348, identifier: "_ZTSN7mozilla13DefaultDeleteIN4base13LaunchOptions12ForkDelegateEEE")
+!3336 = !{!3337, !3341}
+!3337 = !DISubprogram(name: "DefaultDelete", scope: !3335, file: !3326, line: 476, type: !3338, isLocal: false, isDefinition: false, scopeLine: 476, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3338 = !DISubroutineType(types: !3339)
+!3339 = !{null, !3340}
+!3340 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3335, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3341 = !DISubprogram(name: "operator()", linkageName: "_ZNK7mozilla13DefaultDeleteIN4base13LaunchOptions12ForkDelegateEEclEPS3_", scope: !3335, file: !3326, line: 484, type: !3342, isLocal: false, isDefinition: false, scopeLine: 484, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3342 = !DISubroutineType(types: !3343)
+!3343 = !{null, !3344, !3346}
+!3344 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3345, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3345 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3335)
+!3346 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3347, size: 64)
+!3347 = !DICompositeType(tag: DW_TAG_structure_type, name: "ForkDelegate", scope: !3146, file: !3147, line: 119, flags: DIFlagFwdDecl, identifier: "_ZTSN4base13LaunchOptions12ForkDelegateE")
+!3348 = !{!3349}
+!3349 = !DITemplateTypeParameter(name: "T", type: !3347)
+!3350 = !DIDerivedType(tag: DW_TAG_member, name: "mFirstA", scope: !3332, file: !18, line: 78, baseType: !3346, size: 64, flags: DIFlagPrivate)
+!3351 = !DISubprogram(name: "first", linkageName: "_ZN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE5firstEv", scope: !3332, file: !18, line: 67, type: !3352, isLocal: false, isDefinition: false, scopeLine: 67, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3352 = !DISubroutineType(types: !3353)
+!3353 = !{!3354, !3355}
+!3354 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3346, size: 64)
+!3355 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3332, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3356 = !DISubprogram(name: "first", linkageName: "_ZNK7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE5firstEv", scope: !3332, file: !18, line: 68, type: !3357, isLocal: false, isDefinition: false, scopeLine: 68, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3357 = !DISubroutineType(types: !3358)
+!3358 = !{!3359, !3361}
+!3359 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3360, size: 64)
+!3360 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3346)
+!3361 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3362, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3362 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3332)
+!3363 = !DISubprogram(name: "second", linkageName: "_ZN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE6secondEv", scope: !3332, file: !18, line: 69, type: !3364, isLocal: false, isDefinition: false, scopeLine: 69, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3364 = !DISubroutineType(types: !3365)
+!3365 = !{!3366, !3355}
+!3366 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3335, size: 64)
+!3367 = !DISubprogram(name: "second", linkageName: "_ZNK7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE6secondEv", scope: !3332, file: !18, line: 70, type: !3368, isLocal: false, isDefinition: false, scopeLine: 70, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3368 = !DISubroutineType(types: !3369)
+!3369 = !{!3370, !3361}
+!3370 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3345, size: 64)
+!3371 = !DISubprogram(name: "swap", linkageName: "_ZN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE4swapERS9_", scope: !3332, file: !18, line: 72, type: !3372, isLocal: false, isDefinition: false, scopeLine: 72, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true)
+!3372 = !DISubroutineType(types: !3373)
+!3373 = !{null, !3355, !3374}
+!3374 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3332, size: 64)
+!3375 = !{!3376, !3377, !3378, !3379}
+!3376 = !DITemplateTypeParameter(name: "A", type: !3346)
+!3377 = !DITemplateTypeParameter(name: "B", type: !3335)
+!3378 = !DITemplateValueParameter(type: !17, value: i32 1)
+!3379 = !DITemplateValueParameter(type: !17, value: i32 0)
+!3380 = !DISubprogram(name: "Pair", scope: !3329, file: !18, line: 144, type: !3381, isLocal: false, isDefinition: false, scopeLine: 144, flags: DIFlagPrototyped, isOptimized: true)
+!3381 = !DISubroutineType(types: !3382)
+!3382 = !{null, !3383, !3384}
+!3383 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3329, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3384 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3329, size: 64)
+!3385 = !DISubprogram(name: "Pair", scope: !3329, file: !18, line: 147, type: !3386, isLocal: false, isDefinition: false, scopeLine: 147, flags: DIFlagPrototyped, isOptimized: true)
+!3386 = !DISubroutineType(types: !3387)
+!3387 = !{null, !3383, !3388}
+!3388 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3389, size: 64)
+!3389 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3329)
+!3390 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla4PairIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEaSEOS7_", scope: !3329, file: !18, line: 149, type: !3391, isLocal: false, isDefinition: false, scopeLine: 149, flags: DIFlagPrototyped, isOptimized: true)
+!3391 = !DISubroutineType(types: !3392)
+!3392 = !{!3393, !3383, !3384}
+!3393 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3329, size: 64)
+!3394 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla4PairIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEaSERKS7_", scope: !3329, file: !18, line: 158, type: !3395, isLocal: false, isDefinition: false, scopeLine: 158, flags: DIFlagPrototyped, isOptimized: true)
+!3395 = !DISubroutineType(types: !3396)
+!3396 = !{!3393, !3383, !3388}
+!3397 = !DISubprogram(name: "swap", linkageName: "_ZN7mozilla4PairIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE4swapERS7_", scope: !3329, file: !18, line: 166, type: !3398, isLocal: false, isDefinition: false, scopeLine: 166, flags: DIFlagPrototyped, isOptimized: true)
+!3398 = !DISubroutineType(types: !3399)
+!3399 = !{null, !3383, !3393}
+!3400 = !{!3376, !3377}
+!3401 = !DISubprogram(name: "ptr", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3ptrEv", scope: !3325, file: !3326, line: 198, type: !3402, isLocal: false, isDefinition: false, scopeLine: 198, flags: DIFlagPrototyped, isOptimized: true)
+!3402 = !DISubroutineType(types: !3403)
+!3403 = !{!3404, !3414}
+!3404 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3405, size: 64)
+!3405 = !DIDerivedType(tag: DW_TAG_typedef, name: "Pointer", scope: !3325, file: !3326, line: 193, baseType: !3406)
+!3406 = !DIDerivedType(tag: DW_TAG_typedef, name: "Type", scope: !3407, file: !3326, line: 57, baseType: !3410)
+!3407 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "PointerType<base::LaunchOptions::ForkDelegate, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !19, file: !3326, line: 55, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !3408, identifier: "_ZTSN7mozilla6detail11PointerTypeIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EEEE")
+!3408 = !{!3349, !3409}
+!3409 = !DITemplateTypeParameter(name: "D", type: !3335)
+!3410 = !DIDerivedType(tag: DW_TAG_typedef, name: "Type", scope: !3411, file: !3326, line: 51, baseType: !3346)
+!3411 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "PointerTypeImpl<base::LaunchOptions::ForkDelegate, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate>, false>", scope: !19, file: !3326, line: 50, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !3412, identifier: "_ZTSN7mozilla6detail15PointerTypeImplIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELb0EEE")
+!3412 = !{!3349, !3409, !3413}
+!3413 = !DITemplateValueParameter(type: !117, value: i8 0)
+!3414 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3325, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3415 = !DISubprogram(name: "ptr", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3ptrEv", scope: !3325, file: !3326, line: 199, type: !3416, isLocal: false, isDefinition: false, scopeLine: 199, flags: DIFlagPrototyped, isOptimized: true)
+!3416 = !DISubroutineType(types: !3417)
+!3417 = !{!3418, !3420}
+!3418 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3419, size: 64)
+!3419 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3405)
+!3420 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3421, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3421 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3325)
+!3422 = !DISubprogram(name: "del", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3delEv", scope: !3325, file: !3326, line: 201, type: !3423, isLocal: false, isDefinition: false, scopeLine: 201, flags: DIFlagPrototyped, isOptimized: true)
+!3423 = !DISubroutineType(types: !3424)
+!3424 = !{!3425, !3414}
+!3425 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3426, size: 64)
+!3426 = !DIDerivedType(tag: DW_TAG_typedef, name: "DeleterType", scope: !3325, file: !3326, line: 192, baseType: !3335)
+!3427 = !DISubprogram(name: "del", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3delEv", scope: !3325, file: !3326, line: 202, type: !3428, isLocal: false, isDefinition: false, scopeLine: 202, flags: DIFlagPrototyped, isOptimized: true)
+!3428 = !DISubroutineType(types: !3429)
+!3429 = !{!3430, !3420}
+!3430 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3431, size: 64)
+!3431 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3426)
+!3432 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 208, type: !3433, isLocal: false, isDefinition: false, scopeLine: 208, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3433 = !DISubroutineType(types: !3434)
+!3434 = !{null, !3414}
+!3435 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 216, type: !3436, isLocal: false, isDefinition: false, scopeLine: 216, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3436 = !DISubroutineType(types: !3437)
+!3437 = !{null, !3414, !3405}
+!3438 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 221, type: !3439, isLocal: false, isDefinition: false, scopeLine: 221, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3439 = !DISubroutineType(types: !3440)
+!3440 = !{null, !3414, !3405, !3441}
+!3441 = !DIDerivedType(tag: DW_TAG_typedef, name: "Type", scope: !3442, file: !25, line: 1232, baseType: !3370)
+!3442 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Conditional<false, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate>, const mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> &>", scope: !20, file: !25, line: 1231, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !3443, identifier: "_ZTSN7mozilla11ConditionalILb0ENS_13DefaultDeleteIN4base13LaunchOptions12ForkDelegateEEERKS5_EE")
+!3443 = !{!3444, !3445, !3446}
+!3444 = !DITemplateValueParameter(name: "Condition", type: !117, value: i8 0)
+!3445 = !DITemplateTypeParameter(name: "A", type: !3335)
+!3446 = !DITemplateTypeParameter(name: "B", type: !3370)
+!3447 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 247, type: !3448, isLocal: false, isDefinition: false, scopeLine: 247, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3448 = !DISubroutineType(types: !3449)
+!3449 = !{null, !3414, !3405, !3450}
+!3450 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3451, size: 64)
+!3451 = !DIDerivedType(tag: DW_TAG_typedef, name: "Type", scope: !3452, file: !25, line: 864, baseType: !3335)
+!3452 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "RemoveReference<mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !20, file: !25, line: 863, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !3453, identifier: "_ZTSN7mozilla15RemoveReferenceINS_13DefaultDeleteIN4base13LaunchOptions12ForkDelegateEEEEE")
+!3453 = !{!3454}
+!3454 = !DITemplateTypeParameter(name: "T", type: !3335)
+!3455 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 253, type: !3456, isLocal: false, isDefinition: false, scopeLine: 253, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3456 = !DISubroutineType(types: !3457)
+!3457 = !{null, !3414, !3458}
+!3458 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3325, size: 64)
+!3459 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 258, type: !3460, isLocal: false, isDefinition: false, scopeLine: 258, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3460 = !DISubroutineType(types: !3461)
+!3461 = !{null, !3414, !502}
+!3462 = !DISubprogram(name: "~UniquePtr", scope: !3325, file: !3326, line: 274, type: !3433, isLocal: false, isDefinition: false, scopeLine: 274, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3463 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEaSEOS6_", scope: !3325, file: !3326, line: 276, type: !3464, isLocal: false, isDefinition: false, scopeLine: 276, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3464 = !DISubroutineType(types: !3465)
+!3465 = !{!3466, !3414, !3458}
+!3466 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3325, size: 64)
+!3467 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEaSEDn", scope: !3325, file: !3326, line: 295, type: !3468, isLocal: false, isDefinition: false, scopeLine: 295, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3468 = !DISubroutineType(types: !3469)
+!3469 = !{!3466, !3414, !502}
+!3470 = !DISubprogram(name: "operator*", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEdeEv", scope: !3325, file: !3326, line: 300, type: !3471, isLocal: false, isDefinition: false, scopeLine: 300, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3471 = !DISubroutineType(types: !3472)
+!3472 = !{!3473, !3420}
+!3473 = !DIDerivedType(tag: DW_TAG_typedef, name: "Type", scope: !3474, file: !25, line: 894, baseType: !3477)
+!3474 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "AddLvalueReferenceHelper<base::LaunchOptions::ForkDelegate, mozilla::detail::TIsNotVoid>", scope: !19, file: !25, line: 893, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !3475, identifier: "_ZTSN7mozilla6detail24AddLvalueReferenceHelperIN4base13LaunchOptions12ForkDelegateELNS0_8VoidnessE1EEE")
+!3475 = !{!3349, !3476}
+!3476 = !DITemplateValueParameter(name: "V", type: !24, value: i32 1)
+!3477 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3347, size: 64)
+!3478 = !DISubprogram(name: "operator->", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEptEv", scope: !3325, file: !3326, line: 301, type: !3479, isLocal: false, isDefinition: false, scopeLine: 301, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3479 = !DISubroutineType(types: !3480)
+!3480 = !{!3405, !3420}
+!3481 = !DISubprogram(name: "operator bool", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEcvbEv", scope: !3325, file: !3326, line: 306, type: !3482, isLocal: false, isDefinition: false, scopeLine: 306, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3482 = !DISubroutineType(types: !3483)
+!3483 = !{!117, !3420}
+!3484 = !DISubprogram(name: "get", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3getEv", scope: !3325, file: !3326, line: 308, type: !3479, isLocal: false, isDefinition: false, scopeLine: 308, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3485 = !DISubprogram(name: "get_deleter", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE11get_deleterEv", scope: !3325, file: !3326, line: 310, type: !3423, isLocal: false, isDefinition: false, scopeLine: 310, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3486 = !DISubprogram(name: "get_deleter", linkageName: "_ZNK7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE11get_deleterEv", scope: !3325, file: !3326, line: 311, type: !3428, isLocal: false, isDefinition: false, scopeLine: 311, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3487 = !DISubprogram(name: "release", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE7releaseEv", scope: !3325, file: !3326, line: 313, type: !3488, isLocal: false, isDefinition: false, scopeLine: 313, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3488 = !DISubroutineType(types: !3489)
+!3489 = !{!3405, !3414}
+!3490 = !DISubprogram(name: "reset", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE5resetEPS3_", scope: !3325, file: !3326, line: 319, type: !3436, isLocal: false, isDefinition: false, scopeLine: 319, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3491 = !DISubprogram(name: "swap", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE4swapERS6_", scope: !3325, file: !3326, line: 327, type: !3492, isLocal: false, isDefinition: false, scopeLine: 327, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3492 = !DISubroutineType(types: !3493)
+!3493 = !{null, !3414, !3466}
+!3494 = !DISubprogram(name: "UniquePtr", scope: !3325, file: !3326, line: 329, type: !3495, isLocal: false, isDefinition: false, scopeLine: 329, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3495 = !DISubroutineType(types: !3496)
+!3496 = !{null, !3414, !3497}
+!3497 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3421, size: 64)
+!3498 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEaSERKS6_", scope: !3325, file: !3326, line: 330, type: !3495, isLocal: false, isDefinition: false, scopeLine: 330, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3499 = !DILocalVariable(name: "process", scope: !2908, file: !1, line: 35, type: !3500)
+!3500 = !DIDerivedType(tag: DW_TAG_typedef, name: "ProcessHandle", scope: !3148, file: !3501, line: 27, baseType: !3502)
+!3501 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/ipc/chromium/src/base/process.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3502 = !DIDerivedType(tag: DW_TAG_typedef, name: "pid_t", file: !3503, line: 97, baseType: !3504)
+!3503 = !DIFile(filename: "/usr/include/sys/types.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3504 = !DIDerivedType(tag: DW_TAG_typedef, name: "__pid_t", file: !46, line: 152, baseType: !93)
+!3505 = !DILocalVariable(name: "ok", scope: !2908, file: !1, line: 36, type: !117)
+!3506 = !DILocalVariable(name: "stream", scope: !2908, file: !1, line: 44, type: !3507)
+!3507 = !DIDerivedType(tag: DW_TAG_typedef, name: "ScopedCloseFile", scope: !20, file: !3508, line: 80, baseType: !3509)
+!3508 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/FileUtils.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3509 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Scoped<mozilla::ScopedCloseFileTraits>", scope: !20, file: !3510, line: 68, size: 64, flags: DIFlagTypePassByReference, elements: !3511, templateParams: !3570, identifier: "_ZTSN7mozilla6ScopedINS_21ScopedCloseFileTraitsEEE")
+!3510 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/Scoped.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3511 = !{!3512, !3523, !3527, !3532, !3536, !3537, !3542, !3543, !3544, !3548, !3551, !3552, !3555, !3559, !3560, !3563, !3567}
+!3512 = !DIDerivedType(tag: DW_TAG_member, name: "mValue", scope: !3509, file: !3510, line: 154, baseType: !3513, size: 64)
+!3513 = !DIDerivedType(tag: DW_TAG_typedef, name: "Resource", scope: !3509, file: !3510, line: 70, baseType: !3514)
+!3514 = !DIDerivedType(tag: DW_TAG_typedef, name: "type", scope: !3515, file: !3508, line: 72, baseType: !2354)
+!3515 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "ScopedCloseFileTraits", scope: !20, file: !3508, line: 71, size: 8, flags: DIFlagTypePassByValue, elements: !3516, identifier: "_ZTSN7mozilla21ScopedCloseFileTraitsE")
+!3516 = !{!3517, !3520}
+!3517 = !DISubprogram(name: "empty", linkageName: "_ZN7mozilla21ScopedCloseFileTraits5emptyEv", scope: !3515, file: !3508, line: 73, type: !3518, isLocal: false, isDefinition: false, scopeLine: 73, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!3518 = !DISubroutineType(types: !3519)
+!3519 = !{!3514}
+!3520 = !DISubprogram(name: "release", linkageName: "_ZN7mozilla21ScopedCloseFileTraits7releaseEP8_IO_FILE", scope: !3515, file: !3508, line: 74, type: !3521, isLocal: false, isDefinition: false, scopeLine: 74, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!3521 = !DISubroutineType(types: !3522)
+!3522 = !{null, !3514}
+!3523 = !DISubprogram(name: "Scoped", scope: !3509, file: !3510, line: 72, type: !3524, isLocal: false, isDefinition: false, scopeLine: 72, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3524 = !DISubroutineType(types: !3525)
+!3525 = !{null, !3526}
+!3526 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3509, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3527 = !DISubprogram(name: "Scoped", scope: !3509, file: !3510, line: 77, type: !3528, isLocal: false, isDefinition: false, scopeLine: 77, flags: DIFlagPublic | DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3528 = !DISubroutineType(types: !3529)
+!3529 = !{null, !3526, !3530}
+!3530 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3531, size: 64)
+!3531 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3513)
+!3532 = !DISubprogram(name: "Scoped", scope: !3509, file: !3510, line: 83, type: !3533, isLocal: false, isDefinition: false, scopeLine: 83, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3533 = !DISubroutineType(types: !3534)
+!3534 = !{null, !3526, !3535}
+!3535 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3509, size: 64)
+!3536 = !DISubprogram(name: "~Scoped", scope: !3509, file: !3510, line: 89, type: !3524, isLocal: false, isDefinition: false, scopeLine: 89, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3537 = !DISubprogram(name: "operator _IO_FILE *const &", linkageName: "_ZNK7mozilla6ScopedINS_21ScopedCloseFileTraitsEEcvRKP8_IO_FILEEv", scope: !3509, file: !3510, line: 92, type: !3538, isLocal: false, isDefinition: false, scopeLine: 92, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3538 = !DISubroutineType(types: !3539)
+!3539 = !{!3530, !3540}
+!3540 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3541, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3541 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !3509)
+!3542 = !DISubprogram(name: "operator->", linkageName: "_ZNK7mozilla6ScopedINS_21ScopedCloseFileTraitsEEptEv", scope: !3509, file: !3510, line: 93, type: !3538, isLocal: false, isDefinition: false, scopeLine: 93, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3543 = !DISubprogram(name: "get", linkageName: "_ZNK7mozilla6ScopedINS_21ScopedCloseFileTraitsEE3getEv", scope: !3509, file: !3510, line: 94, type: !3538, isLocal: false, isDefinition: false, scopeLine: 94, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3544 = !DISubprogram(name: "rwget", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEE5rwgetEv", scope: !3509, file: !3510, line: 96, type: !3545, isLocal: false, isDefinition: false, scopeLine: 96, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3545 = !DISubroutineType(types: !3546)
+!3546 = !{!3547, !3526}
+!3547 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3513, size: 64)
+!3548 = !DISubprogram(name: "forget", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEE6forgetEv", scope: !3509, file: !3510, line: 107, type: !3549, isLocal: false, isDefinition: false, scopeLine: 107, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3549 = !DISubroutineType(types: !3550)
+!3550 = !{!3513, !3526}
+!3551 = !DISubprogram(name: "dispose", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEE7disposeEv", scope: !3509, file: !3510, line: 118, type: !3524, isLocal: false, isDefinition: false, scopeLine: 118, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3552 = !DISubprogram(name: "operator==", linkageName: "_ZNK7mozilla6ScopedINS_21ScopedCloseFileTraitsEEeqERKP8_IO_FILE", scope: !3509, file: !3510, line: 123, type: !3553, isLocal: false, isDefinition: false, scopeLine: 123, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3553 = !DISubroutineType(types: !3554)
+!3554 = !{!117, !3540, !3530}
+!3555 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEEaSERKP8_IO_FILE", scope: !3509, file: !3510, line: 133, type: !3556, isLocal: false, isDefinition: false, scopeLine: 133, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3556 = !DISubroutineType(types: !3557)
+!3557 = !{!3558, !3526, !3530}
+!3558 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3509, size: 64)
+!3559 = !DISubprogram(name: "reset", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEE5resetERKP8_IO_FILE", scope: !3509, file: !3510, line: 135, type: !3556, isLocal: false, isDefinition: false, scopeLine: 135, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3560 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEEaSEOS2_", scope: !3509, file: !3510, line: 142, type: !3561, isLocal: false, isDefinition: false, scopeLine: 142, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3561 = !DISubroutineType(types: !3562)
+!3562 = !{!3558, !3526, !3535}
+!3563 = !DISubprogram(name: "Scoped", scope: !3509, file: !3510, line: 150, type: !3564, isLocal: false, isDefinition: false, scopeLine: 150, flags: DIFlagExplicit | DIFlagPrototyped, isOptimized: true)
+!3564 = !DISubroutineType(types: !3565)
+!3565 = !{null, !3526, !3566}
+!3566 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !3541, size: 64)
+!3567 = !DISubprogram(name: "operator=", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEEaSERKS2_", scope: !3509, file: !3510, line: 151, type: !3568, isLocal: false, isDefinition: false, scopeLine: 151, flags: DIFlagPrototyped, isOptimized: true)
+!3568 = !DISubroutineType(types: !3569)
+!3569 = !{!3558, !3526, !3566}
+!3570 = !{!3571}
+!3571 = !DITemplateTypeParameter(name: "Traits", type: !3515)
+!3572 = !DILocalVariable(name: "dist", scope: !2908, file: !1, line: 51, type: !3573)
+!3573 = !DICompositeType(tag: DW_TAG_array_type, baseType: !1171, size: 2048, elements: !3574)
+!3574 = !{!3575}
+!3575 = !DISubrange(count: 256)
+!3576 = !DILocalVariable(name: "desc", scope: !2908, file: !1, line: 51, type: !3573)
+!3577 = !DILocalVariable(name: "release", scope: !2908, file: !1, line: 51, type: !3573)
+!3578 = !DILocalVariable(name: "codename", scope: !2908, file: !1, line: 51, type: !3573)
+!3579 = !DILocation(line: 19, column: 32, scope: !2908)
+!3580 = !DILocation(line: 19, column: 58, scope: !2908)
+!3581 = !DILocation(line: 20, column: 32, scope: !2908)
+!3582 = !DILocation(line: 20, column: 54, scope: !2908)
+!3583 = !DILocation(line: 21, column: 7, scope: !3584)
+!3584 = distinct !DILexicalBlock(scope: !2908, file: !1, line: 21, column: 7)
+!3585 = !DILocation(line: 21, column: 37, scope: !3584)
+!3586 = !DILocation(line: 21, column: 7, scope: !2908)
+!3587 = !DILocation(line: 23, column: 3, scope: !2908)
+!3588 = !DILocation(line: 23, column: 7, scope: !2908)
+!3589 = !DILocation(line: 24, column: 12, scope: !3590)
+!3590 = distinct !DILexicalBlock(scope: !2908, file: !1, line: 24, column: 7)
+!3591 = !DILocation(line: 24, column: 7, scope: !3590)
+!3592 = !DILocation(line: 24, column: 20, scope: !3590)
+!3593 = !DILocation(line: 24, column: 7, scope: !2908)
+!3594 = !DILocation(line: 29, column: 3, scope: !2908)
+!3595 = !DILocation(line: 29, column: 35, scope: !2908)
+!3596 = !DILocation(line: 29, column: 36, scope: !2908)
+!3597 = !DILocation(line: 29, column: 53, scope: !2908)
+!3598 = !DILocation(line: 29, column: 28, scope: !2908)
+!3599 = !DILocalVariable(name: "this", arg: 1, scope: !3600, type: !3604, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3600 = distinct !DISubprogram(name: "vector", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEC2ESt16initializer_listIS5_ERKS6_", scope: !2924, file: !49, line: 515, type: !2962, isLocal: false, isDefinition: true, scopeLine: 518, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !2961, retainedNodes: !3601)
+!3601 = !{!3599, !3602, !3603}
+!3602 = !DILocalVariable(name: "__l", arg: 2, scope: !3600, file: !49, line: 515, type: !2964)
+!3603 = !DILocalVariable(name: "__a", arg: 3, scope: !3600, file: !49, line: 516, type: !2934)
+!3604 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2924, size: 64)
+!3605 = !DILocation(line: 0, scope: !3600, inlinedAt: !3606)
+!3606 = distinct !DILocation(line: 29, column: 35, scope: !2908)
+!3607 = !DILocation(line: 516, column: 29, scope: !3600, inlinedAt: !3606)
+!3608 = !DILocalVariable(name: "this", arg: 1, scope: !3609, type: !3612, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3609 = distinct !DISubprogram(name: "_Vector_base", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EEC2ERKS6_", scope: !990, file: !49, line: 251, type: !1127, isLocal: false, isDefinition: true, scopeLine: 252, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1126, retainedNodes: !3610)
+!3610 = !{!3608, !3611}
+!3611 = !DILocalVariable(name: "__a", arg: 2, scope: !3609, file: !49, line: 251, type: !1129)
+!3612 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !990, size: 64)
+!3613 = !DILocation(line: 0, scope: !3609, inlinedAt: !3614)
+!3614 = distinct !DILocation(line: 517, column: 9, scope: !3600, inlinedAt: !3606)
+!3615 = !DILocation(line: 251, column: 42, scope: !3609, inlinedAt: !3614)
+!3616 = !DILocalVariable(name: "this", arg: 1, scope: !3617, type: !3620, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3617 = distinct !DISubprogram(name: "_Vector_impl", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE12_Vector_implC2ERKS6_", scope: !993, file: !49, line: 99, type: !1097, isLocal: false, isDefinition: true, scopeLine: 101, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1096, retainedNodes: !3618)
+!3618 = !{!3616, !3619}
+!3619 = !DILocalVariable(name: "__a", arg: 2, scope: !3617, file: !49, line: 99, type: !1099)
+!3620 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !993, size: 64)
+!3621 = !DILocation(line: 0, scope: !3617, inlinedAt: !3622)
+!3622 = distinct !DILocation(line: 252, column: 9, scope: !3609, inlinedAt: !3614)
+!3623 = !DILocation(line: 99, column: 37, scope: !3617, inlinedAt: !3622)
+!3624 = !DILocation(line: 100, column: 37, scope: !3617, inlinedAt: !3622)
+!3625 = !DILocation(line: 515, column: 43, scope: !3600, inlinedAt: !3606)
+!3626 = !DILocalVariable(name: "this", arg: 1, scope: !3627, type: !3629, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3627 = distinct !DISubprogram(name: "end", linkageName: "_ZNKSt16initializer_listINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE3endEv", scope: !2964, file: !1304, line: 79, type: !2984, isLocal: false, isDefinition: true, scopeLine: 79, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !2986, retainedNodes: !3628)
+!3628 = !{!3626}
+!3629 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !2982, size: 64)
+!3630 = !DILocation(line: 0, scope: !3627, inlinedAt: !3631)
+!3631 = distinct !DILocation(line: 519, column: 39, scope: !3632, inlinedAt: !3606)
+!3632 = distinct !DILexicalBlock(scope: !3600, file: !49, line: 518, column: 7)
+!3633 = !DILocation(line: 79, column: 45, scope: !3627, inlinedAt: !3631)
+!3634 = !DILocation(line: 519, column: 2, scope: !3632, inlinedAt: !3606)
+!3635 = !DILocalVariable(name: "this", arg: 1, scope: !3636, type: !1008, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3636 = distinct !DISubprogram(name: "~basic_string", linkageName: "_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED2Ev", scope: !31, file: !30, line: 656, type: !3637, isLocal: false, isDefinition: true, scopeLine: 657, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3640, retainedNodes: !3641)
+!3637 = !DISubroutineType(types: !3638)
+!3638 = !{null, !3639}
+!3639 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3640 = !DISubprogram(name: "~basic_string", scope: !31, file: !30, line: 656, type: !3637, isLocal: false, isDefinition: false, scopeLine: 656, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true)
+!3641 = !{!3635}
+!3642 = !DILocation(line: 0, scope: !3636, inlinedAt: !3643)
+!3643 = distinct !DILocation(line: 29, column: 35, scope: !2908)
+!3644 = !DILocation(line: 657, column: 9, scope: !3645, inlinedAt: !3643)
+!3645 = distinct !DILexicalBlock(scope: !3636, file: !30, line: 657, column: 7)
+!3646 = !DILocation(line: 31, column: 3, scope: !2908)
+!3647 = !DILocation(line: 31, column: 23, scope: !2908)
+!3648 = !DILocalVariable(name: "this", arg: 1, scope: !3649, type: !3655, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3649 = distinct !DISubprogram(name: "LaunchOptions", linkageName: "_ZN4base13LaunchOptionsC2Ev", scope: !3146, file: !3147, line: 96, type: !3650, isLocal: false, isDefinition: true, scopeLine: 96, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3653, retainedNodes: !3654)
+!3650 = !DISubroutineType(types: !3651)
+!3651 = !{null, !3652}
+!3652 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3146, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3653 = !DISubprogram(name: "LaunchOptions", scope: !3146, type: !3650, isLocal: false, isDefinition: false, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true)
+!3654 = !{!3648}
+!3655 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3146, size: 64)
+!3656 = !DILocation(line: 0, scope: !3649, inlinedAt: !3657)
+!3657 = distinct !DILocation(line: 31, column: 23, scope: !2908)
+!3658 = !DILocation(line: 99, column: 8, scope: !3649, inlinedAt: !3657)
+!3659 = !DILocalVariable(name: "this", arg: 1, scope: !3660, type: !3662, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3660 = distinct !DISubprogram(name: "map", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEEC2Ev", scope: !3153, file: !3154, line: 183, type: !3159, isLocal: false, isDefinition: true, scopeLine: 183, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3158, retainedNodes: !3661)
+!3661 = !{!3659}
+!3662 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3153, size: 64)
+!3663 = !DILocation(line: 0, scope: !3660, inlinedAt: !3664)
+!3664 = distinct !DILocation(line: 96, column: 8, scope: !3649, inlinedAt: !3657)
+!3665 = !DILocalVariable(name: "this", arg: 1, scope: !3666, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3666 = distinct !DISubprogram(name: "_Rb_tree", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EEC2Ev", scope: !303, file: !12, line: 929, type: !832, isLocal: false, isDefinition: true, scopeLine: 929, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !831, retainedNodes: !3667)
+!3667 = !{!3665}
+!3668 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !303, size: 64)
+!3669 = !DILocation(line: 0, scope: !3666, inlinedAt: !3670)
+!3670 = distinct !DILocation(line: 183, column: 7, scope: !3660, inlinedAt: !3664)
+!3671 = !DILocalVariable(name: "this", arg: 1, scope: !3672, type: !3674, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3672 = distinct !DISubprogram(name: "_Rb_tree_impl", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE13_Rb_tree_implISC_Lb1EEC2Ev", scope: !306, file: !12, line: 699, type: !641, isLocal: false, isDefinition: true, scopeLine: 704, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !640, retainedNodes: !3673)
+!3673 = !{!3671}
+!3674 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !306, size: 64)
+!3675 = !DILocation(line: 0, scope: !3672, inlinedAt: !3676)
+!3676 = distinct !DILocation(line: 929, column: 7, scope: !3666, inlinedAt: !3670)
+!3677 = !DILocation(line: 704, column: 4, scope: !3672, inlinedAt: !3676)
+!3678 = !DILocalVariable(name: "this", arg: 1, scope: !3679, type: !3681, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3679 = distinct !DISubprogram(name: "_Rb_tree_header", linkageName: "_ZNSt15_Rb_tree_headerC2Ev", scope: !623, file: !12, line: 173, type: !628, isLocal: false, isDefinition: true, scopeLine: 174, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !627, retainedNodes: !3680)
+!3680 = !{!3678}
+!3681 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !623, size: 64)
+!3682 = !DILocation(line: 0, scope: !3679, inlinedAt: !3683)
+!3683 = distinct !DILocation(line: 699, column: 4, scope: !3672, inlinedAt: !3676)
+!3684 = !DILocation(line: 175, column: 17, scope: !3685, inlinedAt: !3683)
+!3685 = distinct !DILexicalBlock(scope: !3679, file: !12, line: 174, column: 5)
+!3686 = !DILocation(line: 175, column: 26, scope: !3685, inlinedAt: !3683)
+!3687 = !DILocalVariable(name: "this", arg: 1, scope: !3688, type: !3681, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3688 = distinct !DISubprogram(name: "_M_reset", linkageName: "_ZNSt15_Rb_tree_header8_M_resetEv", scope: !623, file: !12, line: 206, type: !628, isLocal: false, isDefinition: true, scopeLine: 207, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !639, retainedNodes: !3689)
+!3689 = !{!3687}
+!3690 = !DILocation(line: 0, scope: !3688, inlinedAt: !3691)
+!3691 = distinct !DILocation(line: 176, column: 7, scope: !3685, inlinedAt: !3683)
+!3692 = !DILocation(line: 208, column: 17, scope: !3688, inlinedAt: !3691)
+!3693 = !DILocation(line: 208, column: 27, scope: !3688, inlinedAt: !3691)
+!3694 = !DILocation(line: 209, column: 17, scope: !3688, inlinedAt: !3691)
+!3695 = !DILocation(line: 209, column: 25, scope: !3688, inlinedAt: !3691)
+!3696 = !DILocation(line: 210, column: 17, scope: !3688, inlinedAt: !3691)
+!3697 = !DILocation(line: 210, column: 26, scope: !3688, inlinedAt: !3691)
+!3698 = !DILocation(line: 211, column: 7, scope: !3688, inlinedAt: !3691)
+!3699 = !DILocation(line: 211, column: 21, scope: !3688, inlinedAt: !3691)
+!3700 = !DILocation(line: 96, column: 8, scope: !3649, inlinedAt: !3657)
+!3701 = !DILocalVariable(name: "this", arg: 1, scope: !3702, type: !3705, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3702 = distinct !DISubprogram(name: "UniquePtr", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEC2EDn", scope: !3325, file: !3326, line: 258, type: !3460, isLocal: false, isDefinition: true, scopeLine: 258, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3459, retainedNodes: !3703)
+!3703 = !{!3701, !3704}
+!3704 = !DILocalVariable(arg: 2, scope: !3702, file: !3326, line: 258, type: !502)
+!3705 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3325, size: 64)
+!3706 = !DILocation(line: 0, scope: !3702, inlinedAt: !3707)
+!3707 = distinct !DILocation(line: 126, column: 52, scope: !3649, inlinedAt: !3657)
+!3708 = !DILocation(line: 258, column: 30, scope: !3702, inlinedAt: !3707)
+!3709 = !DILocalVariable(name: "this", arg: 1, scope: !3710, type: !3722, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3710 = distinct !DISubprogram(name: "Pair<nullptr_t, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", linkageName: "_ZN7mozilla4PairIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEEC2IDnS6_EEOT_OT0_", scope: !3329, file: !18, line: 141, type: !3711, isLocal: false, isDefinition: true, scopeLine: 142, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3716, declaration: !3715, retainedNodes: !3719)
+!3711 = !DISubroutineType(types: !3712)
+!3712 = !{null, !3383, !3713, !3714}
+!3713 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !502, size: 64)
+!3714 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !3335, size: 64)
+!3715 = !DISubprogram(name: "Pair<nullptr_t, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !3329, file: !18, line: 141, type: !3711, isLocal: false, isDefinition: false, scopeLine: 141, flags: DIFlagPrototyped, isOptimized: true, templateParams: !3716)
+!3716 = !{!3717, !3718}
+!3717 = !DITemplateTypeParameter(name: "AArg", type: !502)
+!3718 = !DITemplateTypeParameter(name: "BArg", type: !3335)
+!3719 = !{!3709, !3720, !3721}
+!3720 = !DILocalVariable(name: "aA", arg: 2, scope: !3710, file: !18, line: 141, type: !3713)
+!3721 = !DILocalVariable(name: "aB", arg: 3, scope: !3710, file: !18, line: 141, type: !3714)
+!3722 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3329, size: 64)
+!3723 = !DILocation(line: 0, scope: !3710, inlinedAt: !3724)
+!3724 = distinct !DILocation(line: 258, column: 34, scope: !3702, inlinedAt: !3707)
+!3725 = !DILocation(line: 141, column: 26, scope: !3710, inlinedAt: !3724)
+!3726 = !DILocalVariable(name: "this", arg: 1, scope: !3727, type: !3734, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3727 = distinct !DISubprogram(name: "PairHelper<nullptr_t, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", linkageName: "_ZN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EEC2IDnS7_EEOT_OT0_", scope: !3332, file: !18, line: 64, type: !3728, isLocal: false, isDefinition: true, scopeLine: 65, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3716, declaration: !3730, retainedNodes: !3731)
+!3728 = !DISubroutineType(types: !3729)
+!3729 = !{null, !3355, !3713, !3714}
+!3730 = !DISubprogram(name: "PairHelper<nullptr_t, mozilla::DefaultDelete<base::LaunchOptions::ForkDelegate> >", scope: !3332, file: !18, line: 64, type: !3728, isLocal: false, isDefinition: false, scopeLine: 64, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true, templateParams: !3716)
+!3731 = !{!3726, !3732, !3733}
+!3732 = !DILocalVariable(name: "aA", arg: 2, scope: !3727, file: !18, line: 64, type: !3713)
+!3733 = !DILocalVariable(name: "aB", arg: 3, scope: !3727, file: !18, line: 64, type: !3714)
+!3734 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3332, size: 64)
+!3735 = !DILocation(line: 0, scope: !3727, inlinedAt: !3736)
+!3736 = distinct !DILocation(line: 142, column: 9, scope: !3710, inlinedAt: !3724)
+!3737 = !DILocation(line: 65, column: 36, scope: !3727, inlinedAt: !3736)
+!3738 = !DILocation(line: 32, column: 34, scope: !2908)
+!3739 = !DILocation(line: 32, column: 35, scope: !2908)
+!3740 = !DILocalVariable(name: "this", arg: 1, scope: !3741, type: !70, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3741 = distinct !DISubprogram(name: "pair<int &, int, true>", linkageName: "_ZNSt4pairIiiEC2IRiiLb1EEEOT_OT0_", scope: !71, file: !72, line: 341, type: !3742, isLocal: false, isDefinition: true, scopeLine: 342, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3747, declaration: !3746, retainedNodes: !3749)
+!3742 = !DISubroutineType(types: !3743)
+!3743 = !{null, !100, !3744, !3745}
+!3744 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !93, size: 64)
+!3745 = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: !93, size: 64)
+!3746 = !DISubprogram(name: "pair<int &, int, true>", scope: !71, file: !72, line: 341, type: !3742, isLocal: false, isDefinition: false, scopeLine: 341, flags: DIFlagPrototyped, isOptimized: true, templateParams: !3747)
+!3747 = !{!3748, !94, !658}
+!3748 = !DITemplateTypeParameter(name: "_U1", type: !3744)
+!3749 = !{!3740, !3750, !3751}
+!3750 = !DILocalVariable(name: "__x", arg: 2, scope: !3741, file: !72, line: 341, type: !3744)
+!3751 = !DILocalVariable(name: "__y", arg: 3, scope: !3741, file: !72, line: 341, type: !3745)
+!3752 = !DILocation(line: 0, scope: !3741, inlinedAt: !3753)
+!3753 = distinct !DILocation(line: 32, column: 34, scope: !2908)
+!3754 = !DILocation(line: 341, column: 23, scope: !3741, inlinedAt: !3753)
+!3755 = !DILocation(line: 342, column: 4, scope: !3741, inlinedAt: !3753)
+!3756 = !DILocation(line: 342, column: 10, scope: !3741, inlinedAt: !3753)
+!3757 = !DILocation(line: 342, column: 35, scope: !3741, inlinedAt: !3753)
+!3758 = !DILocalVariable(name: "this", arg: 1, scope: !3759, type: !3762, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3759 = distinct !DISubprogram(name: "push_back", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE9push_backEOS1_", scope: !1263, file: !49, line: 1090, type: !1401, isLocal: false, isDefinition: true, scopeLine: 1091, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1400, retainedNodes: !3760)
+!3760 = !{!3758, !3761}
+!3761 = !DILocalVariable(name: "__x", arg: 2, scope: !3759, file: !49, line: 1090, type: !1403)
+!3762 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1263, size: 64)
+!3763 = !DILocation(line: 0, scope: !3759, inlinedAt: !3764)
+!3764 = distinct !DILocation(line: 32, column: 24, scope: !2908)
+!3765 = !DILocation(line: 1090, column: 30, scope: !3759, inlinedAt: !3764)
+!3766 = !DILocation(line: 1091, column: 9, scope: !3759, inlinedAt: !3764)
+!3767 = !DILocation(line: 32, column: 3, scope: !2908)
+!3768 = !DILocation(line: 33, column: 16, scope: !2908)
+!3769 = !DILocation(line: 35, column: 3, scope: !2908)
+!3770 = !DILocation(line: 35, column: 23, scope: !2908)
+!3771 = !DILocation(line: 36, column: 13, scope: !2908)
+!3772 = !DILocation(line: 37, column: 9, scope: !2908)
+!3773 = !DILocation(line: 37, column: 3, scope: !2908)
+!3774 = !DILocation(line: 0, scope: !3775)
+!3775 = distinct !DILexicalBlock(scope: !3776, file: !1, line: 38, column: 12)
+!3776 = distinct !DILexicalBlock(scope: !2908, file: !1, line: 38, column: 7)
+!3777 = !DILocation(line: 38, column: 7, scope: !2908)
+!3778 = !DILocation(line: 40, column: 5, scope: !3775)
+!3779 = !DILocation(line: 41, column: 5, scope: !3775)
+!3780 = !DILocation(line: 44, column: 26, scope: !2908)
+!3781 = !DILocation(line: 44, column: 19, scope: !2908)
+!3782 = !DILocation(line: 45, column: 8, scope: !3783)
+!3783 = distinct !DILexicalBlock(scope: !2908, file: !1, line: 45, column: 7)
+!3784 = !DILocation(line: 45, column: 7, scope: !2908)
+!3785 = !DILocation(line: 47, column: 11, scope: !3786)
+!3786 = distinct !DILexicalBlock(scope: !3783, file: !1, line: 45, column: 16)
+!3787 = !DILocation(line: 47, column: 5, scope: !3786)
+!3788 = !DILocation(line: 48, column: 5, scope: !3786)
+!3789 = !DILocation(line: 51, column: 3, scope: !2908)
+!3790 = !DILocation(line: 51, column: 8, scope: !2908)
+!3791 = !DILocation(line: 51, column: 19, scope: !2908)
+!3792 = !DILocation(line: 51, column: 30, scope: !2908)
+!3793 = !DILocation(line: 51, column: 44, scope: !2908)
+!3794 = !DILocation(line: 52, column: 7, scope: !3795)
+!3795 = distinct !DILexicalBlock(scope: !2908, file: !1, line: 52, column: 7)
+!3796 = !DILocation(line: 57, column: 45, scope: !3795)
+!3797 = !DILocation(line: 52, column: 7, scope: !2908)
+!3798 = !DILocation(line: 62, column: 16, scope: !2908)
+!3799 = !DILocation(line: 63, column: 16, scope: !2908)
+!3800 = !DILocation(line: 64, column: 12, scope: !2908)
+!3801 = !DILocation(line: 65, column: 13, scope: !2908)
+!3802 = !DILocation(line: 66, column: 3, scope: !2908)
+!3803 = !DILocation(line: 0, scope: !2908)
+!3804 = !DILocation(line: 67, column: 1, scope: !2908)
+!3805 = !DILocation(line: 0, scope: !3786)
+!3806 = !DILocalVariable(name: "this", arg: 1, scope: !3807, type: !3809, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3807 = distinct !DISubprogram(name: "~Scoped", linkageName: "_ZN7mozilla6ScopedINS_21ScopedCloseFileTraitsEED2Ev", scope: !3509, file: !3510, line: 89, type: !3524, isLocal: false, isDefinition: true, scopeLine: 89, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3536, retainedNodes: !3808)
+!3808 = !{!3806}
+!3809 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3509, size: 64)
+!3810 = !DILocation(line: 0, scope: !3807, inlinedAt: !3811)
+!3811 = distinct !DILocation(line: 67, column: 1, scope: !2908)
+!3812 = !DILocation(line: 89, column: 15, scope: !3813, inlinedAt: !3811)
+!3813 = distinct !DILexicalBlock(scope: !3807, file: !3510, line: 89, column: 13)
+!3814 = !DILocation(line: 0, scope: !3815)
+!3815 = distinct !DILexicalBlock(scope: !3795, file: !1, line: 57, column: 51)
+!3816 = !DILocation(line: 0, scope: !3817)
+!3817 = distinct !DILexicalBlock(scope: !3590, file: !1, line: 24, column: 27)
+!3818 = distinct !DISubprogram(name: "~LaunchOptions", linkageName: "_ZN4base13LaunchOptionsD2Ev", scope: !3146, file: !3147, line: 96, type: !3650, isLocal: false, isDefinition: true, scopeLine: 96, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3819, retainedNodes: !3820)
+!3819 = !DISubprogram(name: "~LaunchOptions", scope: !3146, type: !3650, isLocal: false, isDefinition: false, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true)
+!3820 = !{!3821}
+!3821 = !DILocalVariable(name: "this", arg: 1, scope: !3818, type: !3655, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3822 = !DILocation(line: 0, scope: !3818)
+!3823 = !DILocation(line: 96, column: 8, scope: !3824)
+!3824 = distinct !DILexicalBlock(scope: !3818, file: !3147, line: 96, column: 8)
+!3825 = !DILocalVariable(name: "this", arg: 1, scope: !3826, type: !3762, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3826 = distinct !DISubprogram(name: "~vector", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EED2Ev", scope: !1263, file: !49, line: 565, type: !1267, isLocal: false, isDefinition: true, scopeLine: 566, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1305, retainedNodes: !3827)
+!3827 = !{!3825}
+!3828 = !DILocation(line: 0, scope: !3826, inlinedAt: !3829)
+!3829 = distinct !DILocation(line: 96, column: 8, scope: !3824)
+!3830 = !DILocation(line: 567, column: 22, scope: !3831, inlinedAt: !3829)
+!3831 = distinct !DILexicalBlock(scope: !3826, file: !49, line: 566, column: 7)
+!3832 = !DILocation(line: 570, column: 7, scope: !3831, inlinedAt: !3829)
+!3833 = !DILocalVariable(name: "this", arg: 1, scope: !3834, type: !3662, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3834 = distinct !DISubprogram(name: "~map", linkageName: "_ZNSt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4lessIS5_ESaISt4pairIKS5_S5_EEED2Ev", scope: !3153, file: !3154, line: 300, type: !3159, isLocal: false, isDefinition: true, scopeLine: 300, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3193, retainedNodes: !3835)
+!3835 = !{!3833}
+!3836 = !DILocation(line: 0, scope: !3834, inlinedAt: !3837)
+!3837 = distinct !DILocation(line: 96, column: 8, scope: !3824)
+!3838 = !DILocation(line: 300, column: 22, scope: !3839, inlinedAt: !3837)
+!3839 = distinct !DILexicalBlock(scope: !3834, file: !3154, line: 300, column: 22)
+!3840 = !DILocation(line: 96, column: 8, scope: !3818)
+!3841 = distinct !DISubprogram(name: "~vector", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev", scope: !2924, file: !49, line: 565, type: !2928, isLocal: false, isDefinition: true, scopeLine: 566, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !2989, retainedNodes: !3842)
+!3842 = !{!3843}
+!3843 = !DILocalVariable(name: "this", arg: 1, scope: !3841, type: !3604, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3844 = !DILocation(line: 0, scope: !3841)
+!3845 = !DILocation(line: 567, column: 22, scope: !3846)
+!3846 = distinct !DILexicalBlock(scope: !3841, file: !49, line: 566, column: 7)
+!3847 = !DILocation(line: 567, column: 30, scope: !3846)
+!3848 = !DILocation(line: 567, column: 54, scope: !3846)
+!3849 = !DILocalVariable(name: "__first", arg: 1, scope: !3850, file: !3851, line: 203, type: !1008)
+!3850 = distinct !DISubprogram(name: "_Destroy<std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> >", linkageName: "_ZSt8_DestroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EvT_S7_RSaIT0_E", scope: !13, file: !3851, line: 203, type: !3852, isLocal: false, isDefinition: true, scopeLine: 205, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3857, retainedNodes: !3854)
+!3851 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_construct.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3852 = !DISubroutineType(types: !3853)
+!3853 = !{null, !1008, !1008, !1082}
+!3854 = !{!3849, !3855, !3856}
+!3855 = !DILocalVariable(name: "__last", arg: 2, scope: !3850, file: !3851, line: 203, type: !1008)
+!3856 = !DILocalVariable(arg: 3, scope: !3850, file: !3851, line: 204, type: !1082)
+!3857 = !{!3858, !602}
+!3858 = !DITemplateTypeParameter(name: "_ForwardIterator", type: !1008)
+!3859 = !DILocation(line: 203, column: 31, scope: !3850, inlinedAt: !3860)
+!3860 = distinct !DILocation(line: 567, column: 2, scope: !3846)
+!3861 = !DILocation(line: 203, column: 57, scope: !3850, inlinedAt: !3860)
+!3862 = !DILocation(line: 204, column: 22, scope: !3850, inlinedAt: !3860)
+!3863 = !DILocalVariable(name: "__first", arg: 1, scope: !3864, file: !3851, line: 127, type: !1008)
+!3864 = distinct !DISubprogram(name: "_Destroy<std::__cxx11::basic_string<char> *>", linkageName: "_ZSt8_DestroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEvT_S7_", scope: !13, file: !3851, line: 127, type: !3865, isLocal: false, isDefinition: true, scopeLine: 128, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3869, retainedNodes: !3867)
+!3865 = !DISubroutineType(types: !3866)
+!3866 = !{null, !1008, !1008}
+!3867 = !{!3863, !3868}
+!3868 = !DILocalVariable(name: "__last", arg: 2, scope: !3864, file: !3851, line: 127, type: !1008)
+!3869 = !{!3858}
+!3870 = !DILocation(line: 127, column: 31, scope: !3864, inlinedAt: !3871)
+!3871 = distinct !DILocation(line: 206, column: 7, scope: !3850, inlinedAt: !3860)
+!3872 = !DILocation(line: 127, column: 57, scope: !3864, inlinedAt: !3871)
+!3873 = !DILocation(line: 136, column: 7, scope: !3864, inlinedAt: !3871)
+!3874 = !DILocation(line: 570, column: 7, scope: !3846)
+!3875 = !DILocation(line: 570, column: 7, scope: !3841)
+!3876 = distinct !DISubprogram(name: "~UniquePtr", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEED2Ev", scope: !3325, file: !3326, line: 274, type: !3433, isLocal: false, isDefinition: true, scopeLine: 274, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3462, retainedNodes: !3877)
+!3877 = !{!3878}
+!3878 = !DILocalVariable(name: "this", arg: 1, scope: !3876, type: !3705, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3879 = !DILocation(line: 0, scope: !3876)
+!3880 = !DILocalVariable(name: "this", arg: 1, scope: !3881, type: !3705, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3881 = distinct !DISubprogram(name: "reset", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE5resetEPS3_", scope: !3325, file: !3326, line: 319, type: !3436, isLocal: false, isDefinition: true, scopeLine: 319, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3490, retainedNodes: !3882)
+!3882 = !{!3880, !3883, !3884}
+!3883 = !DILocalVariable(name: "aPtr", arg: 2, scope: !3881, file: !3326, line: 319, type: !3405)
+!3884 = !DILocalVariable(name: "old", scope: !3881, file: !3326, line: 320, type: !3405)
+!3885 = !DILocation(line: 0, scope: !3881, inlinedAt: !3886)
+!3886 = distinct !DILocation(line: 274, column: 18, scope: !3887)
+!3887 = distinct !DILexicalBlock(scope: !3876, file: !3326, line: 274, column: 16)
+!3888 = !DILocation(line: 319, column: 22, scope: !3881, inlinedAt: !3886)
+!3889 = !DILocalVariable(name: "this", arg: 1, scope: !3890, type: !3705, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3890 = distinct !DISubprogram(name: "ptr", linkageName: "_ZN7mozilla9UniquePtrIN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS3_EEE3ptrEv", scope: !3325, file: !3326, line: 198, type: !3402, isLocal: false, isDefinition: true, scopeLine: 198, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3401, retainedNodes: !3891)
+!3891 = !{!3889}
+!3892 = !DILocation(line: 0, scope: !3890, inlinedAt: !3893)
+!3893 = distinct !DILocation(line: 320, column: 19, scope: !3881, inlinedAt: !3886)
+!3894 = !DILocalVariable(name: "this", arg: 1, scope: !3895, type: !3734, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3895 = distinct !DISubprogram(name: "first", linkageName: "_ZN7mozilla6detail10PairHelperIPN4base13LaunchOptions12ForkDelegateENS_13DefaultDeleteIS4_EELNS0_11StorageTypeE1ELS8_0EE5firstEv", scope: !3332, file: !18, line: 67, type: !3352, isLocal: false, isDefinition: true, scopeLine: 67, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3351, retainedNodes: !3896)
+!3896 = !{!3894}
+!3897 = !DILocation(line: 0, scope: !3895, inlinedAt: !3898)
+!3898 = distinct !DILocation(line: 198, column: 34, scope: !3890, inlinedAt: !3893)
+!3899 = !DILocation(line: 67, column: 23, scope: !3895, inlinedAt: !3898)
+!3900 = !DILocation(line: 320, column: 19, scope: !3881, inlinedAt: !3886)
+!3901 = !DILocation(line: 320, column: 13, scope: !3881, inlinedAt: !3886)
+!3902 = !DILocation(line: 0, scope: !3890, inlinedAt: !3903)
+!3903 = distinct !DILocation(line: 321, column: 5, scope: !3881, inlinedAt: !3886)
+!3904 = !DILocation(line: 0, scope: !3895, inlinedAt: !3905)
+!3905 = distinct !DILocation(line: 198, column: 34, scope: !3890, inlinedAt: !3903)
+!3906 = !DILocation(line: 321, column: 11, scope: !3881, inlinedAt: !3886)
+!3907 = !DILocation(line: 322, column: 13, scope: !3908, inlinedAt: !3886)
+!3908 = distinct !DILexicalBlock(scope: !3881, file: !3326, line: 322, column: 9)
+!3909 = !DILocation(line: 322, column: 9, scope: !3881, inlinedAt: !3886)
+!3910 = !DILocalVariable(name: "aPtr", arg: 2, scope: !3911, file: !3326, line: 484, type: !3346)
+!3911 = distinct !DISubprogram(name: "operator()", linkageName: "_ZNK7mozilla13DefaultDeleteIN4base13LaunchOptions12ForkDelegateEEclEPS3_", scope: !3335, file: !3326, line: 484, type: !3342, isLocal: false, isDefinition: true, scopeLine: 484, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3341, retainedNodes: !3912)
+!3912 = !{!3913, !3910}
+!3913 = !DILocalVariable(name: "this", arg: 1, scope: !3911, type: !3914, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3914 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3345, size: 64)
+!3915 = !DILocation(line: 484, column: 22, scope: !3911, inlinedAt: !3916)
+!3916 = distinct !DILocation(line: 323, column: 7, scope: !3917, inlinedAt: !3886)
+!3917 = distinct !DILexicalBlock(scope: !3908, file: !3326, line: 322, column: 25)
+!3918 = !DILocation(line: 486, column: 5, scope: !3911, inlinedAt: !3916)
+!3919 = !DILocation(line: 324, column: 5, scope: !3917, inlinedAt: !3886)
+!3920 = !DILocation(line: 274, column: 34, scope: !3876)
+!3921 = distinct !DISubprogram(name: "~_Vector_base", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EED2Ev", scope: !50, file: !49, line: 283, type: !267, isLocal: false, isDefinition: true, scopeLine: 284, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !290, retainedNodes: !3922)
+!3922 = !{!3923}
+!3923 = !DILocalVariable(name: "this", arg: 1, scope: !3921, type: !3924, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3924 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !50, size: 64)
+!3925 = !DILocation(line: 0, scope: !3921)
+!3926 = !DILocation(line: 285, column: 24, scope: !3927)
+!3927 = distinct !DILexicalBlock(scope: !3921, file: !49, line: 284, column: 7)
+!3928 = !DILocalVariable(name: "this", arg: 1, scope: !3929, type: !3924, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3929 = distinct !DISubprogram(name: "_M_deallocate", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE13_M_deallocateEPS1_m", scope: !50, file: !49, line: 300, type: !295, isLocal: false, isDefinition: true, scopeLine: 301, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !294, retainedNodes: !3930)
+!3930 = !{!3928, !3931, !3932}
+!3931 = !DILocalVariable(name: "__p", arg: 2, scope: !3929, file: !49, line: 300, type: !57)
+!3932 = !DILocalVariable(name: "__n", arg: 3, scope: !3929, file: !49, line: 300, type: !175)
+!3933 = !DILocation(line: 0, scope: !3929, inlinedAt: !3934)
+!3934 = distinct !DILocation(line: 285, column: 2, scope: !3927)
+!3935 = !DILocation(line: 300, column: 29, scope: !3929, inlinedAt: !3934)
+!3936 = !DILocation(line: 303, column: 6, scope: !3937, inlinedAt: !3934)
+!3937 = distinct !DILexicalBlock(scope: !3929, file: !49, line: 303, column: 6)
+!3938 = !DILocation(line: 303, column: 6, scope: !3929, inlinedAt: !3934)
+!3939 = !DILocalVariable(name: "__a", arg: 1, scope: !3940, file: !64, line: 461, type: !138)
+!3940 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE10deallocateERS2_PS1_m", scope: !63, file: !64, line: 461, type: !204, isLocal: false, isDefinition: true, scopeLine: 462, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !203, retainedNodes: !3941)
+!3941 = !{!3939, !3942, !3943}
+!3942 = !DILocalVariable(name: "__p", arg: 2, scope: !3940, file: !64, line: 461, type: !69)
+!3943 = !DILocalVariable(name: "__n", arg: 3, scope: !3940, file: !64, line: 461, type: !198)
+!3944 = !DILocation(line: 461, column: 34, scope: !3940, inlinedAt: !3945)
+!3945 = distinct !DILocation(line: 304, column: 4, scope: !3937, inlinedAt: !3934)
+!3946 = !DILocation(line: 461, column: 47, scope: !3940, inlinedAt: !3945)
+!3947 = !DILocalVariable(name: "this", arg: 1, scope: !3948, type: !3952, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3948 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE10deallocateEPS2_m", scope: !146, file: !147, line: 116, type: !181, isLocal: false, isDefinition: true, scopeLine: 117, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !180, retainedNodes: !3949)
+!3949 = !{!3947, !3950, !3951}
+!3950 = !DILocalVariable(name: "__p", arg: 2, scope: !3948, file: !147, line: 116, type: !162)
+!3951 = !DILocalVariable(arg: 3, scope: !3948, file: !147, line: 116, type: !174)
+!3952 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !146, size: 64)
+!3953 = !DILocation(line: 0, scope: !3948, inlinedAt: !3954)
+!3954 = distinct !DILocation(line: 462, column: 13, scope: !3940, inlinedAt: !3945)
+!3955 = !DILocation(line: 116, column: 26, scope: !3948, inlinedAt: !3954)
+!3956 = !DILocation(line: 125, column: 20, scope: !3948, inlinedAt: !3954)
+!3957 = !DILocalVariable(name: "ptr", arg: 1, scope: !3958, file: !3959, line: 150, type: !506)
+!3958 = distinct !DISubprogram(name: "operator delete", linkageName: "_ZdlPv", scope: !3959, file: !3959, line: 149, type: !1698, isLocal: false, isDefinition: true, scopeLine: 150, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !3960)
+!3959 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/mozalloc.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!3960 = !{!3957}
+!3961 = !DILocation(line: 150, column: 11, scope: !3958, inlinedAt: !3962)
+!3962 = distinct !DILocation(line: 125, column: 2, scope: !3948, inlinedAt: !3954)
+!3963 = !DILocation(line: 151, column: 10, scope: !3958, inlinedAt: !3962)
+!3964 = !DILocation(line: 304, column: 4, scope: !3937, inlinedAt: !3934)
+!3965 = !DILocation(line: 287, column: 7, scope: !3921)
+!3966 = distinct !DISubprogram(name: "~_Rb_tree", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EED2Ev", scope: !303, file: !12, line: 964, type: !832, isLocal: false, isDefinition: true, scopeLine: 965, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !858, retainedNodes: !3967)
+!3967 = !{!3968}
+!3968 = !DILocalVariable(name: "this", arg: 1, scope: !3966, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3969 = !DILocation(line: 0, scope: !3966)
+!3970 = !DILocalVariable(name: "this", arg: 1, scope: !3971, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3971 = distinct !DISubprogram(name: "_M_begin", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_beginEv", scope: !303, file: !12, line: 752, type: !676, isLocal: false, isDefinition: true, scopeLine: 753, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !696, retainedNodes: !3972)
+!3972 = !{!3970}
+!3973 = !DILocation(line: 0, scope: !3971, inlinedAt: !3974)
+!3974 = distinct !DILocation(line: 965, column: 18, scope: !3975)
+!3975 = distinct !DILexicalBlock(scope: !3966, file: !12, line: 965, column: 7)
+!3976 = !DILocation(line: 753, column: 40, scope: !3971, inlinedAt: !3974)
+!3977 = !DILocation(line: 753, column: 64, scope: !3971, inlinedAt: !3974)
+!3978 = !DILocation(line: 965, column: 9, scope: !3975)
+!3979 = !DILocation(line: 965, column: 31, scope: !3966)
+!3980 = distinct !DISubprogram(name: "_M_erase", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_M_eraseEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 1867, type: !679, isLocal: false, isDefinition: true, scopeLine: 1868, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !822, retainedNodes: !3981)
+!3981 = !{!3982, !3983, !3984}
+!3982 = !DILocalVariable(name: "this", arg: 1, scope: !3980, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!3983 = !DILocalVariable(name: "__x", arg: 2, scope: !3980, file: !12, line: 906, type: !302)
+!3984 = !DILocalVariable(name: "__y", scope: !3985, file: !12, line: 1873, type: !302)
+!3985 = distinct !DILexicalBlock(scope: !3980, file: !12, line: 1871, column: 2)
+!3986 = !DILocation(line: 0, scope: !3980)
+!3987 = !DILocation(line: 906, column: 27, scope: !3980)
+!3988 = !DILocation(line: 1870, column: 7, scope: !3980)
+!3989 = !DILocation(line: 1870, column: 18, scope: !3980)
+!3990 = !DILocalVariable(name: "__x", arg: 1, scope: !3991, file: !12, line: 787, type: !687)
+!3991 = distinct !DISubprogram(name: "_S_right", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE8_S_rightEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 787, type: !716, isLocal: false, isDefinition: true, scopeLine: 788, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !721, retainedNodes: !3992)
+!3992 = !{!3990}
+!3993 = !DILocation(line: 787, column: 26, scope: !3991, inlinedAt: !3994)
+!3994 = distinct !DILocation(line: 1872, column: 13, scope: !3985)
+!3995 = !DILocation(line: 788, column: 45, scope: !3991, inlinedAt: !3994)
+!3996 = !DILocation(line: 1872, column: 4, scope: !3985)
+!3997 = !DILocalVariable(name: "__x", arg: 1, scope: !3998, file: !12, line: 779, type: !687)
+!3998 = distinct !DISubprogram(name: "_S_left", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE7_S_leftEPSt18_Rb_tree_node_base", scope: !303, file: !12, line: 779, type: !716, isLocal: false, isDefinition: true, scopeLine: 780, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !715, retainedNodes: !3999)
+!3999 = !{!3997}
+!4000 = !DILocation(line: 779, column: 25, scope: !3998, inlinedAt: !4001)
+!4001 = distinct !DILocation(line: 1873, column: 21, scope: !3985)
+!4002 = !DILocation(line: 780, column: 45, scope: !3998, inlinedAt: !4001)
+!4003 = !DILocation(line: 1873, column: 15, scope: !3985)
+!4004 = !DILocation(line: 1874, column: 4, scope: !3985)
+!4005 = distinct !{!4005, !3988, !4006}
+!4006 = !DILocation(line: 1876, column: 2, scope: !3980)
+!4007 = !DILocation(line: 1877, column: 5, scope: !3980)
+!4008 = distinct !DISubprogram(name: "_M_drop_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE12_M_drop_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 667, type: !679, isLocal: false, isDefinition: true, scopeLine: 668, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !682, retainedNodes: !4009)
+!4009 = !{!4010, !4011}
+!4010 = !DILocalVariable(name: "this", arg: 1, scope: !4008, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4011 = !DILocalVariable(name: "__p", arg: 2, scope: !4008, file: !12, line: 667, type: !302)
+!4012 = !DILocation(line: 0, scope: !4008)
+!4013 = !DILocation(line: 667, column: 31, scope: !4008)
+!4014 = !DILocalVariable(name: "this", arg: 1, scope: !4015, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4015 = distinct !DISubprogram(name: "_M_destroy_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE15_M_destroy_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 659, type: !679, isLocal: false, isDefinition: true, scopeLine: 660, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !681, retainedNodes: !4016)
+!4016 = !{!4014, !4017}
+!4017 = !DILocalVariable(name: "__p", arg: 2, scope: !4015, file: !12, line: 659, type: !302)
+!4018 = !DILocation(line: 0, scope: !4015, inlinedAt: !4019)
+!4019 = distinct !DILocation(line: 669, column: 2, scope: !4008)
+!4020 = !DILocation(line: 659, column: 34, scope: !4015, inlinedAt: !4019)
+!4021 = !DILocalVariable(name: "this", arg: 1, scope: !4022, type: !550, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4022 = distinct !DISubprogram(name: "_M_valptr", linkageName: "_ZNSt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_EE9_M_valptrEv", scope: !463, file: !12, line: 234, type: !519, isLocal: false, isDefinition: true, scopeLine: 235, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !518, retainedNodes: !4023)
+!4023 = !{!4021}
+!4024 = !DILocation(line: 0, scope: !4022, inlinedAt: !4025)
+!4025 = distinct !DILocation(line: 661, column: 55, scope: !4015, inlinedAt: !4019)
+!4026 = !DILocation(line: 235, column: 16, scope: !4022, inlinedAt: !4025)
+!4027 = !DILocalVariable(name: "this", arg: 1, scope: !4028, type: !4030, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4028 = distinct !DISubprogram(name: "_M_ptr", linkageName: "_ZN9__gnu_cxx16__aligned_membufISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EE6_M_ptrEv", scope: !486, file: !487, line: 70, type: !513, isLocal: false, isDefinition: true, scopeLine: 71, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !512, retainedNodes: !4029)
+!4029 = !{!4027}
+!4030 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !486, size: 64)
+!4031 = !DILocation(line: 0, scope: !4028, inlinedAt: !4032)
+!4032 = distinct !DILocation(line: 235, column: 27, scope: !4022, inlinedAt: !4025)
+!4033 = !DILocation(line: 71, column: 16, scope: !4028, inlinedAt: !4032)
+!4034 = !DILocalVariable(name: "__a", arg: 1, scope: !4035, file: !64, line: 486, type: !4042)
+!4035 = distinct !DISubprogram(name: "destroy<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE7destroyIS9_EEvRSB_PT_", scope: !4036, file: !64, line: 486, type: !4061, isLocal: false, isDefinition: true, scopeLine: 487, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4064, declaration: !4063, retainedNodes: !4066)
+!4036 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "allocator_traits<std::allocator<std::_Rb_tree_node<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > > > >", scope: !13, file: !64, line: 384, size: 8, flags: DIFlagTypePassByValue, elements: !4037, templateParams: !4059, identifier: "_ZTSSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE")
+!4037 = !{!4038, !4044, !4047, !4050, !4056}
+!4038 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE8allocateERSB_m", scope: !4036, file: !64, line: 435, type: !4039, isLocal: false, isDefinition: false, scopeLine: 435, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!4039 = !DISubroutineType(types: !4040)
+!4040 = !{!4041, !4042, !198}
+!4041 = !DIDerivedType(tag: DW_TAG_typedef, name: "pointer", scope: !4036, file: !64, line: 392, baseType: !550)
+!4042 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !4043, size: 64)
+!4043 = !DIDerivedType(tag: DW_TAG_typedef, name: "allocator_type", scope: !4036, file: !64, line: 387, baseType: !530)
+!4044 = !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE8allocateERSB_mPKv", scope: !4036, file: !64, line: 449, type: !4045, isLocal: false, isDefinition: false, scopeLine: 449, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!4045 = !DISubroutineType(types: !4046)
+!4046 = !{!4041, !4042, !198, !202}
+!4047 = !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE10deallocateERSB_PSA_m", scope: !4036, file: !64, line: 461, type: !4048, isLocal: false, isDefinition: false, scopeLine: 461, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!4048 = !DISubroutineType(types: !4049)
+!4049 = !{null, !4042, !4041, !198}
+!4050 = !DISubprogram(name: "max_size", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE8max_sizeERKSB_", scope: !4036, file: !64, line: 495, type: !4051, isLocal: false, isDefinition: false, scopeLine: 495, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!4051 = !DISubroutineType(types: !4052)
+!4052 = !{!4053, !4054}
+!4053 = !DIDerivedType(tag: DW_TAG_typedef, name: "size_type", scope: !4036, file: !64, line: 407, baseType: !175)
+!4054 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !4055, size: 64)
+!4055 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !4043)
+!4056 = !DISubprogram(name: "select_on_container_copy_construction", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE37select_on_container_copy_constructionERKSB_", scope: !4036, file: !64, line: 504, type: !4057, isLocal: false, isDefinition: false, scopeLine: 504, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true)
+!4057 = !DISubroutineType(types: !4058)
+!4058 = !{!4043, !4054}
+!4059 = !{!4060}
+!4060 = !DITemplateTypeParameter(name: "_Alloc", type: !530)
+!4061 = !DISubroutineType(types: !4062)
+!4062 = !{null, !4042, !321}
+!4063 = !DISubprogram(name: "destroy<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE7destroyIS9_EEvRSB_PT_", scope: !4036, file: !64, line: 486, type: !4061, isLocal: false, isDefinition: false, scopeLine: 486, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true, templateParams: !4064)
+!4064 = !{!4065}
+!4065 = !DITemplateTypeParameter(name: "_Up", type: !322)
+!4066 = !{!4034, !4067}
+!4067 = !DILocalVariable(name: "__p", arg: 2, scope: !4035, file: !64, line: 486, type: !321)
+!4068 = !DILocation(line: 486, column: 26, scope: !4035, inlinedAt: !4069)
+!4069 = distinct !DILocation(line: 661, column: 2, scope: !4015, inlinedAt: !4019)
+!4070 = !DILocation(line: 486, column: 36, scope: !4035, inlinedAt: !4069)
+!4071 = !DILocalVariable(name: "this", arg: 1, scope: !4072, type: !4078, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4072 = distinct !DISubprogram(name: "destroy<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", linkageName: "_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE7destroyISA_EEvPT_", scope: !534, file: !147, line: 140, type: !4073, isLocal: false, isDefinition: true, scopeLine: 140, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4064, declaration: !4075, retainedNodes: !4076)
+!4073 = !DISubroutineType(types: !4074)
+!4074 = !{null, !539, !321}
+!4075 = !DISubprogram(name: "destroy<std::pair<const std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> > >", linkageName: "_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE7destroyISA_EEvPT_", scope: !534, file: !147, line: 140, type: !4073, isLocal: false, isDefinition: false, scopeLine: 140, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true, templateParams: !4064)
+!4076 = !{!4071, !4077}
+!4077 = !DILocalVariable(name: "__p", arg: 2, scope: !4072, file: !147, line: 140, type: !321)
+!4078 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !534, size: 64)
+!4079 = !DILocation(line: 0, scope: !4072, inlinedAt: !4080)
+!4080 = distinct !DILocation(line: 487, column: 8, scope: !4035, inlinedAt: !4069)
+!4081 = !DILocation(line: 140, column: 15, scope: !4072, inlinedAt: !4080)
+!4082 = !DILocation(line: 140, column: 28, scope: !4072, inlinedAt: !4080)
+!4083 = !DILocalVariable(name: "this", arg: 1, scope: !4084, type: !3668, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4084 = distinct !DISubprogram(name: "_M_put_node", linkageName: "_ZNSt8_Rb_treeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt4pairIKS5_S5_ESt10_Select1stIS8_ESt4lessIS5_ESaIS8_EE11_M_put_nodeEPSt13_Rb_tree_nodeIS8_E", scope: !303, file: !12, line: 602, type: !679, isLocal: false, isDefinition: true, scopeLine: 603, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !678, retainedNodes: !4085)
+!4085 = !{!4083, !4086}
+!4086 = !DILocalVariable(name: "__p", arg: 2, scope: !4084, file: !12, line: 602, type: !302)
+!4087 = !DILocation(line: 0, scope: !4084, inlinedAt: !4088)
+!4088 = distinct !DILocation(line: 670, column: 2, scope: !4008)
+!4089 = !DILocation(line: 602, column: 30, scope: !4084, inlinedAt: !4088)
+!4090 = !DILocalVariable(name: "__a", arg: 1, scope: !4091, file: !64, line: 461, type: !4042)
+!4091 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EEEE10deallocateERSB_PSA_m", scope: !4036, file: !64, line: 461, type: !4048, isLocal: false, isDefinition: true, scopeLine: 462, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !4047, retainedNodes: !4092)
+!4092 = !{!4090, !4093, !4094}
+!4093 = !DILocalVariable(name: "__p", arg: 2, scope: !4091, file: !64, line: 461, type: !4041)
+!4094 = !DILocalVariable(name: "__n", arg: 3, scope: !4091, file: !64, line: 461, type: !198)
+!4095 = !DILocation(line: 461, column: 34, scope: !4091, inlinedAt: !4096)
+!4096 = distinct !DILocation(line: 603, column: 9, scope: !4084, inlinedAt: !4088)
+!4097 = !DILocation(line: 461, column: 47, scope: !4091, inlinedAt: !4096)
+!4098 = !DILocation(line: 461, column: 62, scope: !4091, inlinedAt: !4096)
+!4099 = !DILocalVariable(name: "this", arg: 1, scope: !4100, type: !4078, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4100 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt13_Rb_tree_nodeISt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EEE10deallocateEPSB_m", scope: !534, file: !147, line: 116, type: !565, isLocal: false, isDefinition: true, scopeLine: 117, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !564, retainedNodes: !4101)
+!4101 = !{!4099, !4102, !4103}
+!4102 = !DILocalVariable(name: "__p", arg: 2, scope: !4100, file: !147, line: 116, type: !549)
+!4103 = !DILocalVariable(arg: 3, scope: !4100, file: !147, line: 116, type: !174)
+!4104 = !DILocation(line: 0, scope: !4100, inlinedAt: !4105)
+!4105 = distinct !DILocation(line: 462, column: 13, scope: !4091, inlinedAt: !4096)
+!4106 = !DILocation(line: 116, column: 26, scope: !4100, inlinedAt: !4105)
+!4107 = !DILocation(line: 116, column: 40, scope: !4100, inlinedAt: !4105)
+!4108 = !DILocation(line: 125, column: 20, scope: !4100, inlinedAt: !4105)
+!4109 = !DILocation(line: 150, column: 11, scope: !3958, inlinedAt: !4110)
+!4110 = distinct !DILocation(line: 125, column: 2, scope: !4100, inlinedAt: !4105)
+!4111 = !DILocation(line: 151, column: 10, scope: !3958, inlinedAt: !4110)
+!4112 = !DILocation(line: 671, column: 7, scope: !4008)
+!4113 = distinct !DISubprogram(name: "~pair", linkageName: "_ZNSt4pairIKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_ED2Ev", scope: !322, file: !72, line: 193, type: !4114, isLocal: false, isDefinition: true, scopeLine: 193, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !4116, retainedNodes: !4117)
+!4114 = !DISubroutineType(types: !4115)
+!4115 = !{null, !350}
+!4116 = !DISubprogram(name: "~pair", scope: !322, type: !4114, isLocal: false, isDefinition: false, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: true)
+!4117 = !{!4118}
+!4118 = !DILocalVariable(name: "this", arg: 1, scope: !4113, type: !321, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4119 = !DILocation(line: 0, scope: !4113)
+!4120 = !DILocation(line: 193, column: 56, scope: !4121)
+!4121 = distinct !DILexicalBlock(scope: !4113, file: !72, line: 193, column: 56)
+!4122 = !DILocation(line: 0, scope: !3636, inlinedAt: !4123)
+!4123 = distinct !DILocation(line: 193, column: 56, scope: !4121)
+!4124 = !DILocation(line: 657, column: 9, scope: !3645, inlinedAt: !4123)
+!4125 = !DILocation(line: 0, scope: !3636, inlinedAt: !4126)
+!4126 = distinct !DILocation(line: 193, column: 56, scope: !4121)
+!4127 = !DILocation(line: 657, column: 9, scope: !3645, inlinedAt: !4126)
+!4128 = !DILocation(line: 193, column: 56, scope: !4113)
+!4129 = distinct !DISubprogram(name: "~_Vector_base", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EED2Ev", scope: !990, file: !49, line: 283, type: !1124, isLocal: false, isDefinition: true, scopeLine: 284, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1147, retainedNodes: !4130)
+!4130 = !{!4131}
+!4131 = !DILocalVariable(name: "this", arg: 1, scope: !4129, type: !3612, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4132 = !DILocation(line: 0, scope: !4129)
+!4133 = !DILocation(line: 285, column: 24, scope: !4134)
+!4134 = distinct !DILexicalBlock(scope: !4129, file: !49, line: 284, column: 7)
+!4135 = !DILocalVariable(name: "this", arg: 1, scope: !4136, type: !3612, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4136 = distinct !DISubprogram(name: "_M_deallocate", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE13_M_deallocateEPS5_m", scope: !990, file: !49, line: 300, type: !1152, isLocal: false, isDefinition: true, scopeLine: 301, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1151, retainedNodes: !4137)
+!4137 = !{!4135, !4138, !4139}
+!4138 = !DILocalVariable(name: "__p", arg: 2, scope: !4136, file: !49, line: 300, type: !997)
+!4139 = !DILocalVariable(name: "__n", arg: 3, scope: !4136, file: !49, line: 300, type: !175)
+!4140 = !DILocation(line: 0, scope: !4136, inlinedAt: !4141)
+!4141 = distinct !DILocation(line: 285, column: 2, scope: !4134)
+!4142 = !DILocation(line: 300, column: 29, scope: !4136, inlinedAt: !4141)
+!4143 = !DILocation(line: 303, column: 6, scope: !4144, inlinedAt: !4141)
+!4144 = distinct !DILexicalBlock(scope: !4136, file: !49, line: 303, column: 6)
+!4145 = !DILocation(line: 303, column: 6, scope: !4136, inlinedAt: !4141)
+!4146 = !DILocalVariable(name: "__a", arg: 1, scope: !4147, file: !64, line: 461, type: !1009)
+!4147 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE10deallocateERS6_PS5_m", scope: !1002, file: !64, line: 461, type: !1063, isLocal: false, isDefinition: true, scopeLine: 462, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1062, retainedNodes: !4148)
+!4148 = !{!4146, !4149, !4150}
+!4149 = !DILocalVariable(name: "__p", arg: 2, scope: !4147, file: !64, line: 461, type: !1007)
+!4150 = !DILocalVariable(name: "__n", arg: 3, scope: !4147, file: !64, line: 461, type: !198)
+!4151 = !DILocation(line: 461, column: 34, scope: !4147, inlinedAt: !4152)
+!4152 = distinct !DILocation(line: 304, column: 4, scope: !4144, inlinedAt: !4141)
+!4153 = !DILocation(line: 461, column: 47, scope: !4147, inlinedAt: !4152)
+!4154 = !DILocalVariable(name: "this", arg: 1, scope: !4155, type: !4159, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4155 = distinct !DISubprogram(name: "deallocate", linkageName: "_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE10deallocateEPS6_m", scope: !1015, file: !147, line: 116, type: !1044, isLocal: false, isDefinition: true, scopeLine: 117, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1043, retainedNodes: !4156)
+!4156 = !{!4154, !4157, !4158}
+!4157 = !DILocalVariable(name: "__p", arg: 2, scope: !4155, file: !147, line: 116, type: !1030)
+!4158 = !DILocalVariable(arg: 3, scope: !4155, file: !147, line: 116, type: !174)
+!4159 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1015, size: 64)
+!4160 = !DILocation(line: 0, scope: !4155, inlinedAt: !4161)
+!4161 = distinct !DILocation(line: 462, column: 13, scope: !4147, inlinedAt: !4152)
+!4162 = !DILocation(line: 116, column: 26, scope: !4155, inlinedAt: !4161)
+!4163 = !DILocation(line: 125, column: 20, scope: !4155, inlinedAt: !4161)
+!4164 = !DILocation(line: 150, column: 11, scope: !3958, inlinedAt: !4165)
+!4165 = distinct !DILocation(line: 125, column: 2, scope: !4155, inlinedAt: !4161)
+!4166 = !DILocation(line: 151, column: 10, scope: !3958, inlinedAt: !4165)
+!4167 = !DILocation(line: 304, column: 4, scope: !4144, inlinedAt: !4141)
+!4168 = !DILocation(line: 287, column: 7, scope: !4129)
+!4169 = distinct !DISubprogram(name: "__destroy<std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt12_Destroy_auxILb0EE9__destroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvT_S9_", scope: !4170, file: !3851, line: 105, type: !3865, isLocal: false, isDefinition: true, scopeLine: 106, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !3869, declaration: !4172, retainedNodes: !4173)
+!4170 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "_Destroy_aux<false>", scope: !13, file: !3851, line: 101, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !4171, identifier: "_ZTSSt12_Destroy_auxILb0EE")
+!4171 = !{!3413}
+!4172 = !DISubprogram(name: "__destroy<std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt12_Destroy_auxILb0EE9__destroyIPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvT_S9_", scope: !4170, file: !3851, line: 105, type: !3865, isLocal: false, isDefinition: false, scopeLine: 105, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true, templateParams: !3869)
+!4173 = !{!4174, !4175}
+!4174 = !DILocalVariable(name: "__first", arg: 1, scope: !4169, file: !3851, line: 105, type: !1008)
+!4175 = !DILocalVariable(name: "__last", arg: 2, scope: !4169, file: !3851, line: 105, type: !1008)
+!4176 = !DILocation(line: 105, column: 36, scope: !4169)
+!4177 = !DILocation(line: 105, column: 62, scope: !4169)
+!4178 = !DILocation(line: 107, column: 4, scope: !4169)
+!4179 = !DILocation(line: 107, column: 19, scope: !4180)
+!4180 = distinct !DILexicalBlock(scope: !4181, file: !3851, line: 107, column: 4)
+!4181 = distinct !DILexicalBlock(scope: !4169, file: !3851, line: 107, column: 4)
+!4182 = !DILocation(line: 107, column: 4, scope: !4181)
+!4183 = !DILocalVariable(name: "__pointer", arg: 1, scope: !4184, file: !3851, line: 97, type: !1008)
+!4184 = distinct !DISubprogram(name: "_Destroy<std::__cxx11::basic_string<char> >", linkageName: "_ZSt8_DestroyINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEvPT_", scope: !13, file: !3851, line: 97, type: !4185, isLocal: false, isDefinition: true, scopeLine: 98, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !601, retainedNodes: !4187)
+!4185 = !DISubroutineType(types: !4186)
+!4186 = !{null, !1008}
+!4187 = !{!4183}
+!4188 = !DILocation(line: 97, column: 19, scope: !4184, inlinedAt: !4189)
+!4189 = distinct !DILocation(line: 108, column: 6, scope: !4180)
+!4190 = !DILocation(line: 0, scope: !3636, inlinedAt: !4191)
+!4191 = distinct !DILocation(line: 98, column: 19, scope: !4184, inlinedAt: !4189)
+!4192 = !DILocation(line: 657, column: 9, scope: !3645, inlinedAt: !4191)
+!4193 = !DILocation(line: 107, column: 30, scope: !4180)
+!4194 = !DILocation(line: 107, column: 4, scope: !4180)
+!4195 = distinct !{!4195, !4182, !4196}
+!4196 = !DILocation(line: 108, column: 46, scope: !4181)
+!4197 = !DILocation(line: 109, column: 2, scope: !4169)
+!4198 = distinct !DISubprogram(name: "_M_range_initialize<const std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_range_initializeIPKS5_EEvT_SB_St20forward_iterator_tag", scope: !2924, file: !49, line: 1462, type: !4199, isLocal: false, isDefinition: true, scopeLine: 1464, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4206, declaration: !4205, retainedNodes: !4208)
+!4199 = !DISubroutineType(types: !4200)
+!4200 = !{null, !2930, !1038, !1038, !4201}
+!4201 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "forward_iterator_tag", scope: !13, file: !1478, line: 95, size: 8, flags: DIFlagTypePassByValue, elements: !4202, identifier: "_ZTSSt20forward_iterator_tag")
+!4202 = !{!4203}
+!4203 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !4201, baseType: !4204, extraData: i32 0)
+!4204 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "input_iterator_tag", scope: !13, file: !1478, line: 89, size: 8, flags: DIFlagTypePassByValue, elements: !114, identifier: "_ZTSSt18input_iterator_tag")
+!4205 = !DISubprogram(name: "_M_range_initialize<const std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE19_M_range_initializeIPKS5_EEvT_SB_St20forward_iterator_tag", scope: !2924, file: !49, line: 1462, type: !4199, isLocal: false, isDefinition: false, scopeLine: 1462, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true, templateParams: !4206)
+!4206 = !{!4207}
+!4207 = !DITemplateTypeParameter(name: "_ForwardIterator", type: !1038)
+!4208 = !{!4209, !4210, !4211, !4212, !4213}
+!4209 = !DILocalVariable(name: "this", arg: 1, scope: !4198, type: !3604, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4210 = !DILocalVariable(name: "__first", arg: 2, scope: !4198, file: !49, line: 1462, type: !1038)
+!4211 = !DILocalVariable(name: "__last", arg: 3, scope: !4198, file: !49, line: 1462, type: !1038)
+!4212 = !DILocalVariable(arg: 4, scope: !4198, file: !49, line: 1463, type: !4201)
+!4213 = !DILocalVariable(name: "__n", scope: !4198, file: !49, line: 1465, type: !4214)
+!4214 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !1260)
+!4215 = !DILocation(line: 0, scope: !4198)
+!4216 = !DILocation(line: 1462, column: 39, scope: !4198)
+!4217 = !DILocation(line: 1462, column: 65, scope: !4198)
+!4218 = !DILocalVariable(name: "__first", arg: 1, scope: !4219, file: !4220, line: 138, type: !1038)
+!4219 = distinct !DISubprogram(name: "distance<const std::__cxx11::basic_string<char> *>", linkageName: "_ZSt8distanceIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENSt15iterator_traitsIT_E15difference_typeES9_S9_", scope: !13, file: !4220, line: 138, type: !4221, isLocal: false, isDefinition: true, scopeLine: 139, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4229, retainedNodes: !4227)
+!4220 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_iterator_base_funcs.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4221 = !DISubroutineType(types: !4222)
+!4222 = !{!4223, !1038, !1038}
+!4223 = !DIDerivedType(tag: DW_TAG_typedef, name: "difference_type", scope: !4224, file: !1478, line: 193, baseType: !1503)
+!4224 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "iterator_traits<const std::__cxx11::basic_string<char> *>", scope: !13, file: !1478, line: 189, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !4225, identifier: "_ZTSSt15iterator_traitsIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE")
+!4225 = !{!4226}
+!4226 = !DITemplateTypeParameter(name: "_Iterator", type: !1038)
+!4227 = !{!4218, !4228}
+!4228 = !DILocalVariable(name: "__last", arg: 2, scope: !4219, file: !4220, line: 138, type: !1038)
+!4229 = !{!4230}
+!4230 = !DITemplateTypeParameter(name: "_InputIterator", type: !1038)
+!4231 = !DILocation(line: 138, column: 29, scope: !4219, inlinedAt: !4232)
+!4232 = distinct !DILocation(line: 1465, column: 26, scope: !4198)
+!4233 = !DILocation(line: 138, column: 53, scope: !4219, inlinedAt: !4232)
+!4234 = !DILocalVariable(name: "__first", arg: 1, scope: !4235, file: !4220, line: 98, type: !1038)
+!4235 = distinct !DISubprogram(name: "__distance<const std::__cxx11::basic_string<char> *>", linkageName: "_ZSt10__distanceIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENSt15iterator_traitsIT_E15difference_typeES9_S9_St26random_access_iterator_tag", scope: !13, file: !4220, line: 98, type: !4236, isLocal: false, isDefinition: true, scopeLine: 100, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4247, retainedNodes: !4244)
+!4236 = !DISubroutineType(types: !4237)
+!4237 = !{!4223, !1038, !1038, !4238}
+!4238 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "random_access_iterator_tag", scope: !13, file: !1478, line: 103, size: 8, flags: DIFlagTypePassByValue, elements: !4239, identifier: "_ZTSSt26random_access_iterator_tag")
+!4239 = !{!4240}
+!4240 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !4238, baseType: !4241, extraData: i32 0)
+!4241 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bidirectional_iterator_tag", scope: !13, file: !1478, line: 99, size: 8, flags: DIFlagTypePassByValue, elements: !4242, identifier: "_ZTSSt26bidirectional_iterator_tag")
+!4242 = !{!4243}
+!4243 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !4241, baseType: !4201, extraData: i32 0)
+!4244 = !{!4234, !4245, !4246}
+!4245 = !DILocalVariable(name: "__last", arg: 2, scope: !4235, file: !4220, line: 98, type: !1038)
+!4246 = !DILocalVariable(arg: 3, scope: !4235, file: !4220, line: 99, type: !4238)
+!4247 = !{!4248}
+!4248 = !DITemplateTypeParameter(name: "_RandomAccessIterator", type: !1038)
+!4249 = !DILocation(line: 98, column: 38, scope: !4235, inlinedAt: !4250)
+!4250 = distinct !DILocation(line: 141, column: 14, scope: !4219, inlinedAt: !4232)
+!4251 = !DILocation(line: 98, column: 69, scope: !4235, inlinedAt: !4250)
+!4252 = !DILocation(line: 104, column: 21, scope: !4235, inlinedAt: !4250)
+!4253 = !DILocation(line: 1465, column: 20, scope: !4198)
+!4254 = !DILocation(line: 1466, column: 35, scope: !4198)
+!4255 = !DILocation(line: 1466, column: 18, scope: !4198)
+!4256 = !DILocation(line: 1466, column: 27, scope: !4198)
+!4257 = !DILocation(line: 1467, column: 61, scope: !4198)
+!4258 = !DILocation(line: 1467, column: 18, scope: !4198)
+!4259 = !DILocation(line: 1467, column: 36, scope: !4198)
+!4260 = !DILocalVariable(name: "__first", arg: 1, scope: !4261, file: !4262, line: 287, type: !1038)
+!4261 = distinct !DISubprogram(name: "__uninitialized_copy_a<const std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> >", linkageName: "_ZSt22__uninitialized_copy_aIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS5_S5_ET0_T_SA_S9_RSaIT1_E", scope: !13, file: !4262, line: 287, type: !4263, isLocal: false, isDefinition: true, scopeLine: 289, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4269, retainedNodes: !4265)
+!4262 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_uninitialized.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4263 = !DISubroutineType(types: !4264)
+!4264 = !{!1008, !1038, !1038, !1008, !1082}
+!4265 = !{!4260, !4266, !4267, !4268}
+!4266 = !DILocalVariable(name: "__last", arg: 2, scope: !4261, file: !4262, line: 287, type: !1038)
+!4267 = !DILocalVariable(name: "__result", arg: 3, scope: !4261, file: !4262, line: 288, type: !1008)
+!4268 = !DILocalVariable(arg: 4, scope: !4261, file: !4262, line: 288, type: !1082)
+!4269 = !{!4230, !3858, !602}
+!4270 = !DILocation(line: 287, column: 43, scope: !4261, inlinedAt: !4271)
+!4271 = distinct !DILocation(line: 1469, column: 6, scope: !4198)
+!4272 = !DILocation(line: 287, column: 67, scope: !4261, inlinedAt: !4271)
+!4273 = !DILocation(line: 288, column: 24, scope: !4261, inlinedAt: !4271)
+!4274 = !DILocalVariable(name: "__first", arg: 1, scope: !4275, file: !4262, line: 115, type: !1038)
+!4275 = distinct !DISubprogram(name: "uninitialized_copy<const std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> *>", linkageName: "_ZSt18uninitialized_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS5_ET0_T_SA_S9_", scope: !13, file: !4262, line: 115, type: !4276, isLocal: false, isDefinition: true, scopeLine: 117, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4282, retainedNodes: !4278)
+!4276 = !DISubroutineType(types: !4277)
+!4277 = !{!1008, !1038, !1038, !1008}
+!4278 = !{!4274, !4279, !4280, !4281}
+!4279 = !DILocalVariable(name: "__last", arg: 2, scope: !4275, file: !4262, line: 115, type: !1038)
+!4280 = !DILocalVariable(name: "__result", arg: 3, scope: !4275, file: !4262, line: 116, type: !1008)
+!4281 = !DILocalVariable(name: "__assignable", scope: !4275, file: !4262, line: 128, type: !954)
+!4282 = !{!4230, !3858}
+!4283 = !DILocation(line: 115, column: 39, scope: !4275, inlinedAt: !4284)
+!4284 = distinct !DILocation(line: 289, column: 14, scope: !4261, inlinedAt: !4271)
+!4285 = !DILocation(line: 115, column: 63, scope: !4275, inlinedAt: !4284)
+!4286 = !DILocation(line: 116, column: 27, scope: !4275, inlinedAt: !4284)
+!4287 = !DILocation(line: 128, column: 18, scope: !4275, inlinedAt: !4284)
+!4288 = !DILocation(line: 131, column: 14, scope: !4275, inlinedAt: !4284)
+!4289 = !DILocation(line: 1468, column: 18, scope: !4198)
+!4290 = !DILocation(line: 1468, column: 28, scope: !4198)
+!4291 = !DILocation(line: 1472, column: 2, scope: !4198)
+!4292 = distinct !DISubprogram(name: "_M_allocate", linkageName: "_ZNSt12_Vector_baseINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaIS5_EE11_M_allocateEm", scope: !990, file: !49, line: 293, type: !1149, isLocal: false, isDefinition: true, scopeLine: 294, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1148, retainedNodes: !4293)
+!4293 = !{!4294, !4295}
+!4294 = !DILocalVariable(name: "this", arg: 1, scope: !4292, type: !3612, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4295 = !DILocalVariable(name: "__n", arg: 2, scope: !4292, file: !49, line: 293, type: !175)
+!4296 = !DILocation(line: 0, scope: !4292)
+!4297 = !DILocation(line: 293, column: 26, scope: !4292)
+!4298 = !DILocation(line: 296, column: 13, scope: !4292)
+!4299 = !DILocation(line: 296, column: 9, scope: !4292)
+!4300 = !DILocation(line: 296, column: 34, scope: !4292)
+!4301 = !DILocation(line: 296, column: 20, scope: !4292)
+!4302 = !DILocation(line: 296, column: 2, scope: !4292)
+!4303 = distinct !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEE8allocateERS6_m", scope: !1002, file: !64, line: 435, type: !1005, isLocal: false, isDefinition: true, scopeLine: 436, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1004, retainedNodes: !4304)
+!4304 = !{!4305, !4306}
+!4305 = !DILocalVariable(name: "__a", arg: 1, scope: !4303, file: !64, line: 435, type: !1009)
+!4306 = !DILocalVariable(name: "__n", arg: 2, scope: !4303, file: !64, line: 435, type: !198)
+!4307 = !DILocation(line: 435, column: 32, scope: !4303)
+!4308 = !DILocation(line: 435, column: 47, scope: !4303)
+!4309 = !DILocation(line: 436, column: 16, scope: !4303)
+!4310 = !DILocation(line: 436, column: 20, scope: !4303)
+!4311 = !DILocation(line: 436, column: 9, scope: !4303)
+!4312 = distinct !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8allocateEmPKv", scope: !1015, file: !147, line: 99, type: !1041, isLocal: false, isDefinition: true, scopeLine: 100, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1040, retainedNodes: !4313)
+!4313 = !{!4314, !4315, !4316}
+!4314 = !DILocalVariable(name: "this", arg: 1, scope: !4312, type: !4159, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4315 = !DILocalVariable(name: "__n", arg: 2, scope: !4312, file: !147, line: 99, type: !174)
+!4316 = !DILocalVariable(arg: 3, scope: !4312, file: !147, line: 99, type: !178)
+!4317 = !DILocation(line: 0, scope: !4312)
+!4318 = !DILocation(line: 99, column: 26, scope: !4312)
+!4319 = !DILocation(line: 99, column: 43, scope: !4312)
+!4320 = !DILocation(line: 101, column: 10, scope: !4321)
+!4321 = distinct !DILexicalBlock(scope: !4312, file: !147, line: 101, column: 6)
+!4322 = !DILocation(line: 101, column: 6, scope: !4312)
+!4323 = !DILocation(line: 58, column: 3, scope: !4324, inlinedAt: !4326)
+!4324 = distinct !DISubprogram(name: "__throw_bad_alloc", linkageName: "_ZSt17__throw_bad_allocv", scope: !13, file: !4325, line: 56, type: !1652, isLocal: false, isDefinition: true, scopeLine: 57, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true, unit: !0, retainedNodes: !114)
+!4325 = !DIFile(filename: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/dist/include/mozilla/throw_gcc.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4326 = distinct !DILocation(line: 102, column: 4, scope: !4321)
+!4327 = !DILocation(line: 111, column: 46, scope: !4312)
+!4328 = !DILocalVariable(name: "size", arg: 1, scope: !4329, file: !3959, line: 130, type: !1678)
+!4329 = distinct !DISubprogram(name: "operator new", linkageName: "_Znwm", scope: !3959, file: !3959, line: 130, type: !1714, isLocal: false, isDefinition: true, scopeLine: 130, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !4330)
+!4330 = !{!4328}
+!4331 = !DILocation(line: 130, column: 25, scope: !4329, inlinedAt: !4332)
+!4332 = distinct !DILocation(line: 111, column: 27, scope: !4312)
+!4333 = !DILocation(line: 131, column: 10, scope: !4329, inlinedAt: !4332)
+!4334 = !DILocation(line: 111, column: 9, scope: !4312)
+!4335 = !DILocation(line: 111, column: 2, scope: !4312)
+!4336 = distinct !DISubprogram(name: "__uninit_copy<const std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS7_EET0_T_SC_SB_", scope: !4337, file: !4262, line: 76, type: !4276, isLocal: false, isDefinition: true, scopeLine: 78, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4282, declaration: !4340, retainedNodes: !4341)
+!4337 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__uninitialized_copy<false>", scope: !13, file: !4262, line: 72, size: 8, flags: DIFlagTypePassByValue, elements: !114, templateParams: !4338, identifier: "_ZTSSt20__uninitialized_copyILb0EE")
+!4338 = !{!4339}
+!4339 = !DITemplateValueParameter(name: "_TrivialValueTypes", type: !117, value: i8 0)
+!4340 = !DISubprogram(name: "__uninit_copy<const std::__cxx11::basic_string<char> *, std::__cxx11::basic_string<char> *>", linkageName: "_ZNSt20__uninitialized_copyILb0EE13__uninit_copyIPKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPS7_EET0_T_SC_SB_", scope: !4337, file: !4262, line: 76, type: !4276, isLocal: false, isDefinition: false, scopeLine: 76, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true, templateParams: !4282)
+!4341 = !{!4342, !4343, !4344, !4345}
+!4342 = !DILocalVariable(name: "__first", arg: 1, scope: !4336, file: !4262, line: 76, type: !1038)
+!4343 = !DILocalVariable(name: "__last", arg: 2, scope: !4336, file: !4262, line: 76, type: !1038)
+!4344 = !DILocalVariable(name: "__result", arg: 3, scope: !4336, file: !4262, line: 77, type: !1008)
+!4345 = !DILocalVariable(name: "__cur", scope: !4336, file: !4262, line: 79, type: !1008)
+!4346 = !DILocation(line: 76, column: 38, scope: !4336)
+!4347 = !DILocation(line: 76, column: 62, scope: !4336)
+!4348 = !DILocation(line: 77, column: 26, scope: !4336)
+!4349 = !DILocation(line: 79, column: 21, scope: !4336)
+!4350 = !DILocation(line: 82, column: 8, scope: !4351)
+!4351 = distinct !DILexicalBlock(scope: !4352, file: !4262, line: 81, column: 6)
+!4352 = distinct !DILexicalBlock(scope: !4336, file: !4262, line: 80, column: 4)
+!4353 = !DILocation(line: 0, scope: !4354)
+!4354 = distinct !DILexicalBlock(scope: !4355, file: !4262, line: 82, column: 8)
+!4355 = distinct !DILexicalBlock(scope: !4351, file: !4262, line: 82, column: 8)
+!4356 = !DILocation(line: 82, column: 23, scope: !4354)
+!4357 = !DILocation(line: 82, column: 8, scope: !4355)
+!4358 = !DILocalVariable(name: "__p", arg: 1, scope: !4359, file: !3851, line: 74, type: !1008)
+!4359 = distinct !DISubprogram(name: "_Construct<std::__cxx11::basic_string<char>, const std::__cxx11::basic_string<char> &>", linkageName: "_ZSt10_ConstructINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEJRKS5_EEvPT_DpOT0_", scope: !13, file: !3851, line: 74, type: !4360, isLocal: false, isDefinition: true, scopeLine: 75, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4364, retainedNodes: !4362)
+!4360 = !DISubroutineType(types: !4361)
+!4361 = !{null, !1008, !600}
+!4362 = !{!4358, !4363}
+!4363 = !DILocalVariable(name: "__args", arg: 2, scope: !4359, file: !3851, line: 74, type: !600)
+!4364 = !{!4365, !4366}
+!4365 = !DITemplateTypeParameter(name: "_T1", type: !31)
+!4366 = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "_Args", value: !4367)
+!4367 = !{!4368}
+!4368 = !DITemplateTypeParameter(type: !600)
+!4369 = !DILocation(line: 74, column: 21, scope: !4359, inlinedAt: !4370)
+!4370 = distinct !DILocation(line: 83, column: 3, scope: !4354)
+!4371 = !DILocation(line: 74, column: 37, scope: !4359, inlinedAt: !4370)
+!4372 = !DILocation(line: 75, column: 38, scope: !4359, inlinedAt: !4370)
+!4373 = !DILocation(line: 82, column: 34, scope: !4354)
+!4374 = !DILocation(line: 82, column: 51, scope: !4354)
+!4375 = !DILocation(line: 82, column: 8, scope: !4354)
+!4376 = distinct !{!4376, !4357, !4377}
+!4377 = !DILocation(line: 83, column: 53, scope: !4355)
+!4378 = !DILocation(line: 84, column: 8, scope: !4351)
+!4379 = distinct !DISubprogram(name: "emplace_back<std::pair<int, int> >", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE12emplace_backIJS1_EEEvDpOT_", scope: !1263, file: !4380, line: 98, type: !4381, isLocal: false, isDefinition: true, scopeLine: 99, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4384, declaration: !4383, retainedNodes: !4387)
+!4380 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/vector.tcc", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4381 = !DISubroutineType(types: !4382)
+!4382 = !{null, !1269, !106}
+!4383 = !DISubprogram(name: "emplace_back<std::pair<int, int> >", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE12emplace_backIJS1_EEEvDpOT_", scope: !1263, file: !49, line: 1099, type: !4381, isLocal: false, isDefinition: false, scopeLine: 1099, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true, templateParams: !4384)
+!4384 = !{!4385}
+!4385 = !DITemplateValueParameter(tag: DW_TAG_GNU_template_parameter_pack, name: "_Args", value: !4386)
+!4386 = !{!232}
+!4387 = !{!4388, !4389}
+!4388 = !DILocalVariable(name: "this", arg: 1, scope: !4379, type: !3762, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4389 = !DILocalVariable(name: "__args", arg: 2, scope: !4379, file: !49, line: 1099, type: !106)
+!4390 = !DILocation(line: 0, scope: !4379)
+!4391 = !DILocation(line: 1099, column: 26, scope: !4379)
+!4392 = !DILocation(line: 100, column: 20, scope: !4393)
+!4393 = distinct !DILexicalBlock(scope: !4379, file: !4380, line: 100, column: 6)
+!4394 = !DILocation(line: 100, column: 47, scope: !4393)
+!4395 = !DILocation(line: 100, column: 30, scope: !4393)
+!4396 = !DILocation(line: 100, column: 6, scope: !4379)
+!4397 = !DILocalVariable(name: "__a", arg: 1, scope: !4398, file: !64, line: 474, type: !138)
+!4398 = distinct !DISubprogram(name: "construct<std::pair<int, int>, std::pair<int, int> >", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE9constructIS1_JS1_EEEvRS2_PT_DpOT0_", scope: !63, file: !64, line: 474, type: !4399, isLocal: false, isDefinition: true, scopeLine: 475, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4402, declaration: !4401, retainedNodes: !4404)
+!4399 = !DISubroutineType(types: !4400)
+!4400 = !{null, !138, !70, !106}
+!4401 = !DISubprogram(name: "construct<std::pair<int, int>, std::pair<int, int> >", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE9constructIS1_JS1_EEEvRS2_PT_DpOT0_", scope: !63, file: !64, line: 474, type: !4399, isLocal: false, isDefinition: false, scopeLine: 474, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true, templateParams: !4402)
+!4402 = !{!4403, !4385}
+!4403 = !DITemplateTypeParameter(name: "_Up", type: !71)
+!4404 = !{!4397, !4405, !4406}
+!4405 = !DILocalVariable(name: "__p", arg: 2, scope: !4398, file: !64, line: 474, type: !70)
+!4406 = !DILocalVariable(name: "__args", arg: 3, scope: !4398, file: !64, line: 474, type: !106)
+!4407 = !DILocation(line: 474, column: 28, scope: !4398, inlinedAt: !4408)
+!4408 = distinct !DILocation(line: 103, column: 6, scope: !4409)
+!4409 = distinct !DILexicalBlock(scope: !4393, file: !4380, line: 101, column: 4)
+!4410 = !DILocation(line: 474, column: 38, scope: !4398, inlinedAt: !4408)
+!4411 = !DILocation(line: 474, column: 54, scope: !4398, inlinedAt: !4408)
+!4412 = !DILocalVariable(name: "this", arg: 1, scope: !4413, type: !3952, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4413 = distinct !DISubprogram(name: "construct<std::pair<int, int>, std::pair<int, int> >", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE9constructIS2_JS2_EEEvPT_DpOT0_", scope: !146, file: !147, line: 135, type: !4414, isLocal: false, isDefinition: true, scopeLine: 136, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4402, declaration: !4416, retainedNodes: !4417)
+!4414 = !DISubroutineType(types: !4415)
+!4415 = !{null, !152, !70, !106}
+!4416 = !DISubprogram(name: "construct<std::pair<int, int>, std::pair<int, int> >", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE9constructIS2_JS2_EEEvPT_DpOT0_", scope: !146, file: !147, line: 135, type: !4414, isLocal: false, isDefinition: false, scopeLine: 135, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true, templateParams: !4402)
+!4417 = !{!4412, !4418, !4419}
+!4418 = !DILocalVariable(name: "__p", arg: 2, scope: !4413, file: !147, line: 135, type: !70)
+!4419 = !DILocalVariable(name: "__args", arg: 3, scope: !4413, file: !147, line: 135, type: !106)
+!4420 = !DILocation(line: 0, scope: !4413, inlinedAt: !4421)
+!4421 = distinct !DILocation(line: 475, column: 8, scope: !4398, inlinedAt: !4408)
+!4422 = !DILocation(line: 135, column: 17, scope: !4413, inlinedAt: !4421)
+!4423 = !DILocation(line: 135, column: 33, scope: !4413, inlinedAt: !4421)
+!4424 = !DILocation(line: 136, column: 23, scope: !4413, inlinedAt: !4421)
+!4425 = !DILocation(line: 105, column: 6, scope: !4409)
+!4426 = !DILocation(line: 107, column: 4, scope: !4409)
+!4427 = !DILocation(line: 109, column: 4, scope: !4393)
+!4428 = !DILocation(line: 113, column: 7, scope: !4379)
+!4429 = distinct !DISubprogram(name: "_M_realloc_insert<std::pair<int, int> >", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_realloc_insertIJS1_EEEvN9__gnu_cxx17__normal_iteratorIPS1_S3_EEDpOT_", scope: !1263, file: !4380, line: 414, type: !4430, isLocal: false, isDefinition: true, scopeLine: 421, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4384, declaration: !4432, retainedNodes: !4433)
+!4430 = !DISubroutineType(types: !4431)
+!4431 = !{null, !1269, !1262, !106}
+!4432 = !DISubprogram(name: "_M_realloc_insert<std::pair<int, int> >", linkageName: "_ZNSt6vectorISt4pairIiiESaIS1_EE17_M_realloc_insertIJS1_EEEvN9__gnu_cxx17__normal_iteratorIPS1_S3_EEDpOT_", scope: !1263, file: !49, line: 1621, type: !4430, isLocal: false, isDefinition: false, scopeLine: 1621, flags: DIFlagProtected | DIFlagPrototyped, isOptimized: true, templateParams: !4384)
+!4433 = !{!4434, !4435, !4436, !4437, !4438, !4439, !4440, !4441, !4442}
+!4434 = !DILocalVariable(name: "this", arg: 1, scope: !4429, type: !3762, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4435 = !DILocalVariable(name: "__position", arg: 2, scope: !4429, file: !49, line: 1621, type: !1262)
+!4436 = !DILocalVariable(name: "__args", arg: 3, scope: !4429, file: !49, line: 1621, type: !106)
+!4437 = !DILocalVariable(name: "__len", scope: !4429, file: !4380, line: 422, type: !4214)
+!4438 = !DILocalVariable(name: "__old_start", scope: !4429, file: !4380, line: 424, type: !1448)
+!4439 = !DILocalVariable(name: "__old_finish", scope: !4429, file: !4380, line: 425, type: !1448)
+!4440 = !DILocalVariable(name: "__elems_before", scope: !4429, file: !4380, line: 426, type: !4214)
+!4441 = !DILocalVariable(name: "__new_start", scope: !4429, file: !4380, line: 427, type: !1448)
+!4442 = !DILocalVariable(name: "__new_finish", scope: !4429, file: !4380, line: 428, type: !1448)
+!4443 = !DILocation(line: 0, scope: !4429)
+!4444 = !DILocation(line: 1621, column: 52, scope: !4429)
+!4445 = !DILocation(line: 423, column: 2, scope: !4429)
+!4446 = !DILocation(line: 422, column: 23, scope: !4429)
+!4447 = !DILocation(line: 424, column: 35, scope: !4429)
+!4448 = !DILocation(line: 424, column: 43, scope: !4429)
+!4449 = !DILocation(line: 424, column: 15, scope: !4429)
+!4450 = !DILocation(line: 425, column: 44, scope: !4429)
+!4451 = !DILocation(line: 425, column: 15, scope: !4429)
+!4452 = !DILocation(line: 426, column: 53, scope: !4429)
+!4453 = !DILocation(line: 1621, column: 29, scope: !4429)
+!4454 = !DILocalVariable(name: "__lhs", arg: 1, scope: !4455, file: !879, line: 966, type: !4458)
+!4455 = distinct !DISubprogram(name: "operator-<std::pair<int, int> *, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >", linkageName: "_ZN9__gnu_cxxmiIPSt4pairIiiESt6vectorIS2_SaIS2_EEEENS_17__normal_iteratorIT_T0_E15difference_typeERKSA_SD_", scope: !5, file: !879, line: 966, type: !4456, isLocal: false, isDefinition: true, scopeLine: 969, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !1516, retainedNodes: !4459)
+!4456 = !DISubroutineType(types: !4457)
+!4457 = !{!1501, !4458, !4458}
+!4458 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1483, size: 64)
+!4459 = !{!4454, !4460}
+!4460 = !DILocalVariable(name: "__rhs", arg: 2, scope: !4455, file: !879, line: 967, type: !4458)
+!4461 = !DILocation(line: 966, column: 63, scope: !4455, inlinedAt: !4462)
+!4462 = distinct !DILocation(line: 426, column: 51, scope: !4429)
+!4463 = !DILocation(line: 967, column: 56, scope: !4455, inlinedAt: !4462)
+!4464 = !DILocation(line: 969, column: 27, scope: !4455, inlinedAt: !4462)
+!4465 = !DILocation(line: 426, column: 23, scope: !4429)
+!4466 = !DILocation(line: 427, column: 33, scope: !4429)
+!4467 = !DILocation(line: 427, column: 15, scope: !4429)
+!4468 = !DILocation(line: 428, column: 15, scope: !4429)
+!4469 = !DILocation(line: 437, column: 20, scope: !4470)
+!4470 = distinct !DILexicalBlock(scope: !4471, file: !4380, line: 430, column: 2)
+!4471 = distinct !DILexicalBlock(scope: !4429, file: !4380, line: 429, column: 7)
+!4472 = !DILocation(line: 474, column: 28, scope: !4398, inlinedAt: !4473)
+!4473 = distinct !DILocation(line: 436, column: 4, scope: !4470)
+!4474 = !DILocation(line: 474, column: 38, scope: !4398, inlinedAt: !4473)
+!4475 = !DILocation(line: 474, column: 54, scope: !4398, inlinedAt: !4473)
+!4476 = !DILocation(line: 0, scope: !4413, inlinedAt: !4477)
+!4477 = distinct !DILocation(line: 475, column: 8, scope: !4398, inlinedAt: !4473)
+!4478 = !DILocation(line: 135, column: 17, scope: !4413, inlinedAt: !4477)
+!4479 = !DILocation(line: 135, column: 33, scope: !4413, inlinedAt: !4477)
+!4480 = !DILocation(line: 136, column: 23, scope: !4413, inlinedAt: !4477)
+!4481 = !DILocalVariable(name: "__first", arg: 1, scope: !4482, file: !4262, line: 305, type: !70)
+!4482 = distinct !DISubprogram(name: "__uninitialized_move_if_noexcept_a<std::pair<int, int> *, std::pair<int, int> *, std::allocator<std::pair<int, int> > >", linkageName: "_ZSt34__uninitialized_move_if_noexcept_aIPSt4pairIiiES2_SaIS1_EET0_T_S5_S4_RT1_", scope: !13, file: !4262, line: 305, type: !4483, isLocal: false, isDefinition: true, scopeLine: 309, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4489, retainedNodes: !4485)
+!4483 = !DISubroutineType(types: !4484)
+!4484 = !{!70, !70, !70, !70, !223}
+!4485 = !{!4481, !4486, !4487, !4488}
+!4486 = !DILocalVariable(name: "__last", arg: 2, scope: !4482, file: !4262, line: 306, type: !70)
+!4487 = !DILocalVariable(name: "__result", arg: 3, scope: !4482, file: !4262, line: 307, type: !70)
+!4488 = !DILocalVariable(name: "__alloc", arg: 4, scope: !4482, file: !4262, line: 308, type: !223)
+!4489 = !{!4490, !4491, !4492}
+!4490 = !DITemplateTypeParameter(name: "_InputIterator", type: !70)
+!4491 = !DITemplateTypeParameter(name: "_ForwardIterator", type: !70)
+!4492 = !DITemplateTypeParameter(name: "_Allocator", type: !140)
+!4493 = !DILocation(line: 305, column: 55, scope: !4482, inlinedAt: !4494)
+!4494 = distinct !DILocation(line: 446, column: 8, scope: !4470)
+!4495 = !DILocation(line: 306, column: 27, scope: !4482, inlinedAt: !4494)
+!4496 = !DILocation(line: 307, column: 29, scope: !4482, inlinedAt: !4494)
+!4497 = !DILocalVariable(name: "__first", arg: 1, scope: !4498, file: !4262, line: 287, type: !1518)
+!4498 = distinct !DISubprogram(name: "__uninitialized_copy_a<std::move_iterator<std::pair<int, int> *>, std::pair<int, int> *, std::pair<int, int> >", linkageName: "_ZSt22__uninitialized_copy_aISt13move_iteratorIPSt4pairIiiEES3_S2_ET0_T_S6_S5_RSaIT1_E", scope: !13, file: !4262, line: 287, type: !4499, isLocal: false, isDefinition: true, scopeLine: 289, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4505, retainedNodes: !4501)
+!4499 = !DISubroutineType(types: !4500)
+!4500 = !{!70, !1518, !1518, !70, !223}
+!4501 = !{!4497, !4502, !4503, !4504}
+!4502 = !DILocalVariable(name: "__last", arg: 2, scope: !4498, file: !4262, line: 287, type: !1518)
+!4503 = !DILocalVariable(name: "__result", arg: 3, scope: !4498, file: !4262, line: 288, type: !70)
+!4504 = !DILocalVariable(arg: 4, scope: !4498, file: !4262, line: 288, type: !223)
+!4505 = !{!4506, !4491, !187}
+!4506 = !DITemplateTypeParameter(name: "_InputIterator", type: !1518)
+!4507 = !DILocation(line: 287, column: 43, scope: !4498, inlinedAt: !4508)
+!4508 = distinct !DILocation(line: 310, column: 14, scope: !4482, inlinedAt: !4494)
+!4509 = !DILocation(line: 287, column: 67, scope: !4498, inlinedAt: !4508)
+!4510 = !DILocation(line: 288, column: 24, scope: !4498, inlinedAt: !4508)
+!4511 = !DILocalVariable(name: "__first", arg: 1, scope: !4512, file: !4262, line: 115, type: !1518)
+!4512 = distinct !DISubprogram(name: "uninitialized_copy<std::move_iterator<std::pair<int, int> *>, std::pair<int, int> *>", linkageName: "_ZSt18uninitialized_copyISt13move_iteratorIPSt4pairIiiEES3_ET0_T_S6_S5_", scope: !13, file: !4262, line: 115, type: !4513, isLocal: false, isDefinition: true, scopeLine: 117, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4519, retainedNodes: !4515)
+!4513 = !DISubroutineType(types: !4514)
+!4514 = !{!70, !1518, !1518, !70}
+!4515 = !{!4511, !4516, !4517, !4518}
+!4516 = !DILocalVariable(name: "__last", arg: 2, scope: !4512, file: !4262, line: 115, type: !1518)
+!4517 = !DILocalVariable(name: "__result", arg: 3, scope: !4512, file: !4262, line: 116, type: !70)
+!4518 = !DILocalVariable(name: "__assignable", scope: !4512, file: !4262, line: 128, type: !954)
+!4519 = !{!4506, !4491}
+!4520 = !DILocation(line: 115, column: 39, scope: !4512, inlinedAt: !4521)
+!4521 = distinct !DILocation(line: 289, column: 14, scope: !4498, inlinedAt: !4508)
+!4522 = !DILocation(line: 115, column: 63, scope: !4512, inlinedAt: !4521)
+!4523 = !DILocation(line: 116, column: 27, scope: !4512, inlinedAt: !4521)
+!4524 = !DILocation(line: 128, column: 18, scope: !4512, inlinedAt: !4521)
+!4525 = !DILocalVariable(name: "__result", arg: 3, scope: !4526, file: !4262, line: 77, type: !70)
+!4526 = distinct !DISubprogram(name: "__uninit_copy<std::move_iterator<std::pair<int, int> *>, std::pair<int, int> *>", linkageName: "_ZNSt20__uninitialized_copyILb0EE13__uninit_copyISt13move_iteratorIPSt4pairIiiEES5_EET0_T_S8_S7_", scope: !4337, file: !4262, line: 76, type: !4513, isLocal: false, isDefinition: true, scopeLine: 78, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4519, declaration: !4527, retainedNodes: !4528)
+!4527 = !DISubprogram(name: "__uninit_copy<std::move_iterator<std::pair<int, int> *>, std::pair<int, int> *>", linkageName: "_ZNSt20__uninitialized_copyILb0EE13__uninit_copyISt13move_iteratorIPSt4pairIiiEES5_EET0_T_S8_S7_", scope: !4337, file: !4262, line: 76, type: !4513, isLocal: false, isDefinition: false, scopeLine: 76, flags: DIFlagPrototyped | DIFlagStaticMember, isOptimized: true, templateParams: !4519)
+!4528 = !{!4529, !4530, !4525, !4531}
+!4529 = !DILocalVariable(name: "__first", arg: 1, scope: !4526, file: !4262, line: 76, type: !1518)
+!4530 = !DILocalVariable(name: "__last", arg: 2, scope: !4526, file: !4262, line: 76, type: !1518)
+!4531 = !DILocalVariable(name: "__cur", scope: !4526, file: !4262, line: 79, type: !70)
+!4532 = !DILocation(line: 77, column: 26, scope: !4526, inlinedAt: !4533)
+!4533 = distinct !DILocation(line: 131, column: 14, scope: !4512, inlinedAt: !4521)
+!4534 = !DILocation(line: 79, column: 21, scope: !4526, inlinedAt: !4533)
+!4535 = !DILocation(line: 82, column: 8, scope: !4536, inlinedAt: !4533)
+!4536 = distinct !DILexicalBlock(scope: !4537, file: !4262, line: 81, column: 6)
+!4537 = distinct !DILexicalBlock(scope: !4526, file: !4262, line: 80, column: 4)
+!4538 = !DILocation(line: 0, scope: !4539, inlinedAt: !4533)
+!4539 = distinct !DILexicalBlock(scope: !4540, file: !4262, line: 82, column: 8)
+!4540 = distinct !DILexicalBlock(scope: !4536, file: !4262, line: 82, column: 8)
+!4541 = !DILocation(line: 76, column: 38, scope: !4526, inlinedAt: !4533)
+!4542 = !DILocation(line: 76, column: 62, scope: !4526, inlinedAt: !4533)
+!4543 = !DILocalVariable(name: "__x", arg: 1, scope: !4544, file: !879, line: 1133, type: !4547)
+!4544 = distinct !DISubprogram(name: "operator!=<std::pair<int, int> *>", linkageName: "_ZStneIPSt4pairIiiEEbRKSt13move_iteratorIT_ES7_", scope: !13, file: !879, line: 1133, type: !4545, isLocal: false, isDefinition: true, scopeLine: 1135, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !1480, retainedNodes: !4548)
+!4545 = !DISubroutineType(types: !4546)
+!4546 = !{!117, !4547, !4547}
+!4547 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !1533, size: 64)
+!4548 = !{!4543, !4549}
+!4549 = !DILocalVariable(name: "__y", arg: 2, scope: !4544, file: !879, line: 1134, type: !4547)
+!4550 = !DILocation(line: 1133, column: 48, scope: !4544, inlinedAt: !4551)
+!4551 = distinct !DILocation(line: 82, column: 23, scope: !4539, inlinedAt: !4533)
+!4552 = !DILocation(line: 1134, column: 41, scope: !4544, inlinedAt: !4551)
+!4553 = !DILocalVariable(name: "__x", arg: 1, scope: !4554, file: !879, line: 1121, type: !4547)
+!4554 = distinct !DISubprogram(name: "operator==<std::pair<int, int> *>", linkageName: "_ZSteqIPSt4pairIiiEEbRKSt13move_iteratorIT_ES7_", scope: !13, file: !879, line: 1121, type: !4545, isLocal: false, isDefinition: true, scopeLine: 1123, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !1480, retainedNodes: !4555)
+!4555 = !{!4553, !4556}
+!4556 = !DILocalVariable(name: "__y", arg: 2, scope: !4554, file: !879, line: 1122, type: !4547)
+!4557 = !DILocation(line: 1121, column: 48, scope: !4554, inlinedAt: !4558)
+!4558 = distinct !DILocation(line: 1135, column: 20, scope: !4544, inlinedAt: !4551)
+!4559 = !DILocation(line: 1122, column: 41, scope: !4554, inlinedAt: !4558)
+!4560 = !DILocation(line: 1123, column: 25, scope: !4554, inlinedAt: !4558)
+!4561 = !DILocation(line: 82, column: 8, scope: !4540, inlinedAt: !4533)
+!4562 = !DILocalVariable(name: "__p", arg: 1, scope: !4563, file: !3851, line: 74, type: !70)
+!4563 = distinct !DISubprogram(name: "_Construct<std::pair<int, int>, std::pair<int, int> >", linkageName: "_ZSt10_ConstructISt4pairIiiEJS1_EEvPT_DpOT0_", scope: !13, file: !3851, line: 74, type: !4564, isLocal: false, isDefinition: true, scopeLine: 75, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4568, retainedNodes: !4566)
+!4564 = !DISubroutineType(types: !4565)
+!4565 = !{null, !70, !106}
+!4566 = !{!4562, !4567}
+!4567 = !DILocalVariable(name: "__args", arg: 2, scope: !4563, file: !3851, line: 74, type: !106)
+!4568 = !{!4569, !4385}
+!4569 = !DITemplateTypeParameter(name: "_T1", type: !71)
+!4570 = !DILocation(line: 74, column: 21, scope: !4563, inlinedAt: !4571)
+!4571 = distinct !DILocation(line: 83, column: 3, scope: !4539, inlinedAt: !4533)
+!4572 = !DILocation(line: 74, column: 37, scope: !4563, inlinedAt: !4571)
+!4573 = !DILocation(line: 75, column: 38, scope: !4563, inlinedAt: !4571)
+!4574 = !DILocalVariable(name: "this", arg: 1, scope: !4575, type: !4577, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4575 = distinct !DISubprogram(name: "operator++", linkageName: "_ZNSt13move_iteratorIPSt4pairIiiEEppEv", scope: !1518, file: !879, line: 1054, type: !1547, isLocal: false, isDefinition: true, scopeLine: 1055, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1546, retainedNodes: !4576)
+!4576 = !{!4574}
+!4577 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1518, size: 64)
+!4578 = !DILocation(line: 0, scope: !4575, inlinedAt: !4579)
+!4579 = distinct !DILocation(line: 82, column: 34, scope: !4539, inlinedAt: !4533)
+!4580 = !DILocation(line: 1056, column: 2, scope: !4575, inlinedAt: !4579)
+!4581 = !DILocation(line: 82, column: 51, scope: !4539, inlinedAt: !4533)
+!4582 = !DILocation(line: 82, column: 8, scope: !4539, inlinedAt: !4533)
+!4583 = distinct !{!4583, !4584, !4585}
+!4584 = !DILocation(line: 82, column: 8, scope: !4540)
+!4585 = !DILocation(line: 83, column: 53, scope: !4540)
+!4586 = !DILocation(line: 450, column: 4, scope: !4470)
+!4587 = !DILocation(line: 305, column: 55, scope: !4482, inlinedAt: !4588)
+!4588 = distinct !DILocation(line: 453, column: 8, scope: !4470)
+!4589 = !DILocation(line: 306, column: 27, scope: !4482, inlinedAt: !4588)
+!4590 = !DILocation(line: 307, column: 29, scope: !4482, inlinedAt: !4588)
+!4591 = !DILocation(line: 287, column: 43, scope: !4498, inlinedAt: !4592)
+!4592 = distinct !DILocation(line: 310, column: 14, scope: !4482, inlinedAt: !4588)
+!4593 = !DILocation(line: 287, column: 67, scope: !4498, inlinedAt: !4592)
+!4594 = !DILocation(line: 288, column: 24, scope: !4498, inlinedAt: !4592)
+!4595 = !DILocation(line: 115, column: 39, scope: !4512, inlinedAt: !4596)
+!4596 = distinct !DILocation(line: 289, column: 14, scope: !4498, inlinedAt: !4592)
+!4597 = !DILocation(line: 115, column: 63, scope: !4512, inlinedAt: !4596)
+!4598 = !DILocation(line: 116, column: 27, scope: !4512, inlinedAt: !4596)
+!4599 = !DILocation(line: 128, column: 18, scope: !4512, inlinedAt: !4596)
+!4600 = !DILocation(line: 77, column: 26, scope: !4526, inlinedAt: !4601)
+!4601 = distinct !DILocation(line: 131, column: 14, scope: !4512, inlinedAt: !4596)
+!4602 = !DILocation(line: 79, column: 21, scope: !4526, inlinedAt: !4601)
+!4603 = !DILocation(line: 82, column: 8, scope: !4536, inlinedAt: !4601)
+!4604 = !DILocation(line: 0, scope: !4539, inlinedAt: !4601)
+!4605 = !DILocation(line: 76, column: 38, scope: !4526, inlinedAt: !4601)
+!4606 = !DILocation(line: 76, column: 62, scope: !4526, inlinedAt: !4601)
+!4607 = !DILocation(line: 1133, column: 48, scope: !4544, inlinedAt: !4608)
+!4608 = distinct !DILocation(line: 82, column: 23, scope: !4539, inlinedAt: !4601)
+!4609 = !DILocation(line: 1134, column: 41, scope: !4544, inlinedAt: !4608)
+!4610 = !DILocation(line: 1121, column: 48, scope: !4554, inlinedAt: !4611)
+!4611 = distinct !DILocation(line: 1135, column: 20, scope: !4544, inlinedAt: !4608)
+!4612 = !DILocation(line: 1122, column: 41, scope: !4554, inlinedAt: !4611)
+!4613 = !DILocation(line: 1123, column: 25, scope: !4554, inlinedAt: !4611)
+!4614 = !DILocation(line: 82, column: 8, scope: !4540, inlinedAt: !4601)
+!4615 = !DILocation(line: 74, column: 21, scope: !4563, inlinedAt: !4616)
+!4616 = distinct !DILocation(line: 83, column: 3, scope: !4539, inlinedAt: !4601)
+!4617 = !DILocation(line: 74, column: 37, scope: !4563, inlinedAt: !4616)
+!4618 = !DILocation(line: 75, column: 38, scope: !4563, inlinedAt: !4616)
+!4619 = !DILocation(line: 0, scope: !4575, inlinedAt: !4620)
+!4620 = distinct !DILocation(line: 82, column: 34, scope: !4539, inlinedAt: !4601)
+!4621 = !DILocation(line: 1056, column: 2, scope: !4575, inlinedAt: !4620)
+!4622 = !DILocation(line: 82, column: 51, scope: !4539, inlinedAt: !4601)
+!4623 = !DILocation(line: 82, column: 8, scope: !4539, inlinedAt: !4601)
+!4624 = !DILocation(line: 470, column: 21, scope: !4429)
+!4625 = !DILocation(line: 0, scope: !3929, inlinedAt: !4626)
+!4626 = distinct !DILocation(line: 469, column: 7, scope: !4429)
+!4627 = !DILocation(line: 300, column: 29, scope: !3929, inlinedAt: !4626)
+!4628 = !DILocation(line: 303, column: 6, scope: !3937, inlinedAt: !4626)
+!4629 = !DILocation(line: 303, column: 6, scope: !3929, inlinedAt: !4626)
+!4630 = !DILocation(line: 461, column: 34, scope: !3940, inlinedAt: !4631)
+!4631 = distinct !DILocation(line: 304, column: 4, scope: !3937, inlinedAt: !4626)
+!4632 = !DILocation(line: 461, column: 47, scope: !3940, inlinedAt: !4631)
+!4633 = !DILocation(line: 0, scope: !3948, inlinedAt: !4634)
+!4634 = distinct !DILocation(line: 462, column: 13, scope: !3940, inlinedAt: !4631)
+!4635 = !DILocation(line: 116, column: 26, scope: !3948, inlinedAt: !4634)
+!4636 = !DILocation(line: 125, column: 20, scope: !3948, inlinedAt: !4634)
+!4637 = !DILocation(line: 150, column: 11, scope: !3958, inlinedAt: !4638)
+!4638 = distinct !DILocation(line: 125, column: 2, scope: !3948, inlinedAt: !4634)
+!4639 = !DILocation(line: 151, column: 10, scope: !3958, inlinedAt: !4638)
+!4640 = !DILocation(line: 304, column: 4, scope: !3937, inlinedAt: !4626)
+!4641 = !DILocation(line: 471, column: 30, scope: !4429)
+!4642 = !DILocation(line: 472, column: 31, scope: !4429)
+!4643 = !DILocation(line: 473, column: 53, scope: !4429)
+!4644 = !DILocation(line: 473, column: 39, scope: !4429)
+!4645 = !DILocation(line: 474, column: 5, scope: !4429)
+!4646 = distinct !DISubprogram(name: "_M_check_len", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE12_M_check_lenEmPKc", scope: !1263, file: !49, line: 1640, type: !1440, isLocal: false, isDefinition: true, scopeLine: 1641, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1439, retainedNodes: !4647)
+!4647 = !{!4648, !4650, !4651, !4652}
+!4648 = !DILocalVariable(name: "this", arg: 1, scope: !4646, type: !4649, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4649 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !1289, size: 64)
+!4650 = !DILocalVariable(name: "__n", arg: 2, scope: !4646, file: !49, line: 1640, type: !1260)
+!4651 = !DILocalVariable(name: "__s", arg: 3, scope: !4646, file: !49, line: 1640, type: !1443)
+!4652 = !DILocalVariable(name: "__len", scope: !4646, file: !49, line: 1645, type: !4214)
+!4653 = !DILocation(line: 0, scope: !4646)
+!4654 = !DILocation(line: 1640, column: 30, scope: !4646)
+!4655 = !DILocation(line: 1640, column: 47, scope: !4646)
+!4656 = !DILocalVariable(name: "this", arg: 1, scope: !4657, type: !4649, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4657 = distinct !DISubprogram(name: "size", linkageName: "_ZNKSt6vectorISt4pairIiiESaIS1_EE4sizeEv", scope: !1263, file: !49, line: 805, type: !1350, isLocal: false, isDefinition: true, scopeLine: 806, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !1349, retainedNodes: !4658)
+!4658 = !{!4656}
+!4659 = !DILocation(line: 0, scope: !4657, inlinedAt: !4660)
+!4660 = distinct !DILocation(line: 1642, column: 19, scope: !4661)
+!4661 = distinct !DILexicalBlock(scope: !4646, file: !49, line: 1642, column: 6)
+!4662 = !DILocation(line: 806, column: 40, scope: !4657, inlinedAt: !4660)
+!4663 = !DILocation(line: 806, column: 66, scope: !4657, inlinedAt: !4660)
+!4664 = !DILocation(line: 806, column: 50, scope: !4657, inlinedAt: !4660)
+!4665 = !DILocation(line: 1642, column: 17, scope: !4661)
+!4666 = !DILocation(line: 1642, column: 26, scope: !4661)
+!4667 = !DILocation(line: 1642, column: 6, scope: !4646)
+!4668 = !DILocalVariable(name: "msg", arg: 1, scope: !4669, file: !4325, line: 93, type: !1443)
+!4669 = distinct !DISubprogram(name: "__throw_length_error", linkageName: "_ZSt20__throw_length_errorPKc", scope: !13, file: !4325, line: 92, type: !2429, isLocal: false, isDefinition: true, scopeLine: 93, flags: DIFlagPrototyped | DIFlagNoReturn, isOptimized: true, unit: !0, retainedNodes: !4670)
+!4670 = !{!4668}
+!4671 = !DILocation(line: 93, column: 17, scope: !4669, inlinedAt: !4672)
+!4672 = distinct !DILocation(line: 1643, column: 4, scope: !4661)
+!4673 = !DILocation(line: 94, column: 3, scope: !4669, inlinedAt: !4672)
+!4674 = !DILocation(line: 0, scope: !4657, inlinedAt: !4675)
+!4675 = distinct !DILocation(line: 1645, column: 26, scope: !4646)
+!4676 = !DILocation(line: 0, scope: !4657, inlinedAt: !4677)
+!4677 = distinct !DILocation(line: 1645, column: 44, scope: !4646)
+!4678 = !DILocation(line: 224, column: 15, scope: !4679, inlinedAt: !4692)
+!4679 = distinct !DILexicalBlock(scope: !4681, file: !4680, line: 224, column: 11)
+!4680 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/stl_algobase.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4681 = distinct !DISubprogram(name: "max<unsigned long>", linkageName: "_ZSt3maxImERKT_S2_S2_", scope: !13, file: !4680, line: 219, type: !4682, isLocal: false, isDefinition: true, scopeLine: 220, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !4690, retainedNodes: !4686)
+!4682 = !DISubroutineType(types: !4683)
+!4683 = !{!4684, !4684, !4684}
+!4684 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !4685, size: 64)
+!4685 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !177)
+!4686 = !{!4687, !4689}
+!4687 = !DILocalVariable(name: "__a", arg: 1, scope: !4681, file: !4688, line: 370, type: !4684)
+!4688 = !DIFile(filename: "/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../include/c++/8.2.1/bits/algorithmfwd.h", directory: "/home/firefox/firefox/mozilla-unified/obj-opt-x86_64-pc-linux-gnu/widget")
+!4689 = !DILocalVariable(name: "__b", arg: 2, scope: !4681, file: !4688, line: 370, type: !4684)
+!4690 = !{!4691}
+!4691 = !DITemplateTypeParameter(name: "_Tp", type: !177)
+!4692 = distinct !DILocation(line: 1645, column: 35, scope: !4646)
+!4693 = !DILocation(line: 1645, column: 35, scope: !4646)
+!4694 = !DILocation(line: 1645, column: 33, scope: !4646)
+!4695 = !DILocation(line: 1645, column: 18, scope: !4646)
+!4696 = !DILocation(line: 0, scope: !4657, inlinedAt: !4697)
+!4697 = distinct !DILocation(line: 1646, column: 18, scope: !4646)
+!4698 = !DILocation(line: 1646, column: 16, scope: !4646)
+!4699 = !DILocation(line: 1646, column: 34, scope: !4646)
+!4700 = !DILocation(line: 1646, column: 25, scope: !4646)
+!4701 = !DILocation(line: 1646, column: 2, scope: !4646)
+!4702 = distinct !DISubprogram(name: "_M_allocate", linkageName: "_ZNSt12_Vector_baseISt4pairIiiESaIS1_EE11_M_allocateEm", scope: !50, file: !49, line: 293, type: !292, isLocal: false, isDefinition: true, scopeLine: 294, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !291, retainedNodes: !4703)
+!4703 = !{!4704, !4705}
+!4704 = !DILocalVariable(name: "this", arg: 1, scope: !4702, type: !3924, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4705 = !DILocalVariable(name: "__n", arg: 2, scope: !4702, file: !49, line: 293, type: !175)
+!4706 = !DILocation(line: 0, scope: !4702)
+!4707 = !DILocation(line: 293, column: 26, scope: !4702)
+!4708 = !DILocation(line: 296, column: 13, scope: !4702)
+!4709 = !DILocation(line: 296, column: 9, scope: !4702)
+!4710 = !DILocation(line: 296, column: 34, scope: !4702)
+!4711 = !DILocation(line: 296, column: 20, scope: !4702)
+!4712 = !DILocation(line: 296, column: 2, scope: !4702)
+!4713 = distinct !DISubprogram(name: "allocate", linkageName: "_ZNSt16allocator_traitsISaISt4pairIiiEEE8allocateERS2_m", scope: !63, file: !64, line: 435, type: !67, isLocal: false, isDefinition: true, scopeLine: 436, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !66, retainedNodes: !4714)
+!4714 = !{!4715, !4716}
+!4715 = !DILocalVariable(name: "__a", arg: 1, scope: !4713, file: !64, line: 435, type: !138)
+!4716 = !DILocalVariable(name: "__n", arg: 2, scope: !4713, file: !64, line: 435, type: !198)
+!4717 = !DILocation(line: 435, column: 32, scope: !4713)
+!4718 = !DILocation(line: 435, column: 47, scope: !4713)
+!4719 = !DILocation(line: 436, column: 16, scope: !4713)
+!4720 = !DILocation(line: 436, column: 20, scope: !4713)
+!4721 = !DILocation(line: 436, column: 9, scope: !4713)
+!4722 = distinct !DISubprogram(name: "allocate", linkageName: "_ZN9__gnu_cxx13new_allocatorISt4pairIiiEE8allocateEmPKv", scope: !146, file: !147, line: 99, type: !172, isLocal: false, isDefinition: true, scopeLine: 100, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !171, retainedNodes: !4723)
+!4723 = !{!4724, !4725, !4726}
+!4724 = !DILocalVariable(name: "this", arg: 1, scope: !4722, type: !3952, flags: DIFlagArtificial | DIFlagObjectPointer)
+!4725 = !DILocalVariable(name: "__n", arg: 2, scope: !4722, file: !147, line: 99, type: !174)
+!4726 = !DILocalVariable(arg: 3, scope: !4722, file: !147, line: 99, type: !178)
+!4727 = !DILocation(line: 0, scope: !4722)
+!4728 = !DILocation(line: 99, column: 26, scope: !4722)
+!4729 = !DILocation(line: 99, column: 43, scope: !4722)
+!4730 = !DILocation(line: 101, column: 10, scope: !4731)
+!4731 = distinct !DILexicalBlock(scope: !4722, file: !147, line: 101, column: 6)
+!4732 = !DILocation(line: 101, column: 6, scope: !4722)
+!4733 = !DILocation(line: 58, column: 3, scope: !4324, inlinedAt: !4734)
+!4734 = distinct !DILocation(line: 102, column: 4, scope: !4731)
+!4735 = !DILocation(line: 111, column: 46, scope: !4722)
+!4736 = !DILocation(line: 130, column: 25, scope: !4329, inlinedAt: !4737)
+!4737 = distinct !DILocation(line: 111, column: 27, scope: !4722)
+!4738 = !DILocation(line: 131, column: 10, scope: !4329, inlinedAt: !4737)
+!4739 = !DILocation(line: 111, column: 9, scope: !4722)
+!4740 = !DILocation(line: 111, column: 2, scope: !4722)
+!4741 = distinct !DISubprogram(name: "release", linkageName: "_ZN7mozilla21ScopedCloseFileTraits7releaseEP8_IO_FILE", scope: !3515, file: !3508, line: 74, type: !3521, isLocal: false, isDefinition: true, scopeLine: 74, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !3520, retainedNodes: !4742)
+!4742 = !{!4743}
+!4743 = !DILocalVariable(name: "aFile", arg: 1, scope: !4741, file: !3508, line: 74, type: !3514)
+!4744 = !DILocation(line: 74, column: 28, scope: !4741)
+!4745 = !DILocation(line: 75, column: 9, scope: !4746)
+!4746 = distinct !DILexicalBlock(scope: !4741, file: !3508, line: 75, column: 9)
+!4747 = !DILocation(line: 75, column: 9, scope: !4741)
+!4748 = !DILocation(line: 76, column: 7, scope: !4749)
+!4749 = distinct !DILexicalBlock(scope: !4746, file: !3508, line: 75, column: 16)
+!4750 = !DILocation(line: 77, column: 5, scope: !4749)
+!4751 = !DILocation(line: 78, column: 3, scope: !4741)
diff --git a/test/debug_metadata_4.ll b/test/debug_metadata_4.ll
new file mode 100644
# file too large to diff: test/debug_metadata_4.ll
diff --git a/test/debug_metadata_5.ll b/test/debug_metadata_5.ll
new file mode 100644
# file too large to diff: test/debug_metadata_5.ll
diff --git a/test/main_return_38.c b/test/main_return_38.c
new file mode 100644
--- /dev/null
+++ b/test/main_return_38.c
@@ -0,0 +1,3 @@
+int main() {
+  return 38;
+}
