diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -20,6 +20,10 @@
 ppllvm :: Module -> Text
 ```
 
+Individual LLVM elements (constants, instructions) can be printed using the
+the polymorphic ``ppll`` function for any LLVM structure that implements the
+``PP`` typeclass.
+
 Tests
 -----
 
@@ -144,5 +148,5 @@
 
 Released under the MIT License.
 
-Copyright (c) 2014-2017, Stephen Diehl
+Copyright (c) 2014-2018, Stephen Diehl
 Copyright (c) 2015 Cedric Shock
diff --git a/llvm-hs-pretty.cabal b/llvm-hs-pretty.cabal
--- a/llvm-hs-pretty.cabal
+++ b/llvm-hs-pretty.cabal
@@ -1,5 +1,5 @@
 name:                llvm-hs-pretty
-version:             0.3.0.0
+version:             0.4.0.0
 license:             MIT
 synopsis:            A pretty printer for LLVM IR. 
 description:         A pretty printer for the LLVM AST types provided by llvm-hs.
@@ -10,7 +10,7 @@
 category:            Compilers
 cabal-version:       >=1.10
 homepage:            https://github.com/llvm-hs/llvm-hs-pretty
-extra-source-files:  README.md ChangeLog.md
+extra-source-files:  README.md ChangeLog.md tests/input/*.ll
 
 Source-Repository head
     Type: git
diff --git a/src/LLVM/Pretty.hs b/src/LLVM/Pretty.hs
--- a/src/LLVM/Pretty.hs
+++ b/src/LLVM/Pretty.hs
@@ -34,6 +34,7 @@
 import qualified LLVM.AST.Constant as C
 import qualified LLVM.AST.FloatingPointPredicate as FP
 import qualified LLVM.AST.IntegerPredicate as IP
+import qualified LLVM.AST.InlineAssembly as IA
 import qualified LLVM.AST.AddrSpace as AS
 import qualified LLVM.AST.Float as F
 import qualified LLVM.AST.RMWOperation as RMW
@@ -51,7 +52,7 @@
 import qualified Data.ByteString.Lazy.Char8 as BF
 import Data.ByteString.Lazy (fromStrict)
 import Data.ByteString.Internal (w2c)
-import Text.PrettyPrint.Leijen.Text hiding (column, line)
+import Text.PrettyPrint.Leijen.Text hiding (column, line, (<>))
 
 import qualified Data.ByteString.Char8 as BL
 import qualified Data.ByteString.Short as BS
@@ -60,6 +61,7 @@
 import Data.Int
 import Data.List (intersperse)
 import Data.Maybe (isJust, mapMaybe)
+import Data.Monoid ((<>))
 import Numeric (showHex)
 
 import Data.Array.Unsafe
@@ -316,6 +318,7 @@
    SanitizeAddress     -> "sanitize_address"
    SanitizeThread      -> "sanitize_thread"
    SanitizeMemory      -> "sanitize_memory"
+   SanitizeHWAddress   -> "sanitize_hwaddress"
    NoRecurse           -> "norecurse"
    Convergent          -> "convergent"
    ArgMemOnly          -> "argmemonly"
@@ -325,6 +328,7 @@
    InaccessibleMemOrArgMemOnly -> "inaccessiblemem_or_argmemonly"
    FA.StringAttribute k v -> dquotes (short k) <> "=" <> dquotes (short v)
    Speculatable        -> "speculatable"
+   StrictFP            -> "strictfp"
 
 instance PP ParameterAttribute where
   pp = \case
@@ -1062,6 +1066,7 @@
   pp C.PtrToInt {..} = "ptrtoint" <+> parens (ppTyped operand0 <+> "to" <+> pp type')
   pp C.IntToPtr {..} = "inttoptr" <+> parens (ppTyped operand0 <+> "to" <+> pp type')
   pp C.AddrSpaceCast {..} = "addrspacecast" <+> parens (ppTyped operand0 <+> "to" <+> pp type')
+  pp _ = error "Non-function argument. (Malformed AST)"
 
 instance PP a => PP (Named a) where
   pp (nm := a) = "%" <> pp nm <+> "=" <+> pp a
@@ -1217,6 +1222,22 @@
         Just MustTail -> "musttail"
         Just NoTail -> "notail"
         Nothing -> empty
+ppCall Call { function = Left (IA.InlineAssembly {..}), ..}
+  = tail <+> "call" <+> pp callingConvention <+> pp returnAttributes <+> pp type'
+    <+> "asm" <+> sideeffect' <+> align' <+> dialect' <+> dquotes (text (pack (BL.unpack assembly))) <> ","
+    <+> dquotes (pp constraints) <> parens (commas $ fmap pp arguments) <+> pp functionAttributes
+    where
+      tail = case tailCallKind of
+        Just Tail -> "tail"
+        Just MustTail -> "musttail"
+        Just NoTail -> "notail"
+        Nothing -> empty
+      -- If multiple keywords appear the ‘sideeffect‘ keyword must come first,
+      -- the ‘alignstack‘ keyword second and the ‘inteldialect‘ keyword last.
+      sideeffect' = if hasSideEffects then "sideeffect" else ""
+      align' = if alignStack then "alignstack" else ""
+      -- ATTDialect is assumed if not specified
+      dialect' = case dialect of IA.ATTDialect -> ""; IA.IntelDialect -> "inteldialect"
 ppCall x = error "Non-callable argument. (Malformed AST)"
 
 -- Differs from Call in record name conventions only so needs a seperate almost
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -46,6 +46,7 @@
 suite :: IO TestTree
 suite = do
   dirFiles <- listDirectory testPath
+  createDirectoryIfMissing True "tests/output"
   let testFiles = fmap (\x -> testPath </> x) dirFiles
   pure $ testGroup "Test Suite" [
     testGroup "Roundtrip Tests" $ fmap makeTest testFiles
diff --git a/tests/input/asm.ll b/tests/input/asm.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/asm.ll
@@ -0,0 +1,14 @@
+; ModuleID = '<string>'
+
+
+define external ccc i64 @main(){
+entry:
+  %X = alloca i64
+  store i64 1, i64* %X
+  %Y = load i64, i64* %X
+  %A = call i64 (i64) asm "addq $0, $0", "=r,r"(i64 %Y)
+  %B = call i64 (i64) asm alignstack inteldialect "sub $0, $0", "=r,r"(i64 %Y)
+  %C = call i64 asm alignstack "movq $$1, $0", "=r"()
+  %D = call i64 (i64) asm sideeffect "add $$1, $0", "=r,r"(i64  %Y)
+  ret i64 %D
+}
diff --git a/tests/input/cast.ll b/tests/input/cast.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/cast.ll
@@ -0,0 +1,5 @@
+define void @main() {
+  %X = uitofp i32 257 to float;
+  %Y = uitofp i8 -1 to double;
+  ret void
+}
diff --git a/tests/input/clang.ll b/tests/input/clang.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/clang.ll
@@ -0,0 +1,25 @@
+; ModuleID = 'hello.c'
+source_filename = "hello.c"
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+@.str = private unnamed_addr constant [12 x i8] c"Hello World\00", align 1
+
+; Function Attrs: noinline nounwind uwtable
+define i32 @main(i32, i8**) #0 {
+  %3 = alloca i32, align 4
+  %4 = alloca i32, align 4
+  %5 = alloca i8**, align 8
+  store i32 0, i32* %3, align 4
+  store i32 %0, i32* %4, align 4
+  store i8** %1, i8*** %5, align 8
+  %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...) #1
+
+attributes #0 = { noinline nounwind 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 = { "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-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" }
+
+!0 = !{!"clang version 4.0.0-svn297204-1~exp1 (branches/release_40)"}
diff --git a/tests/input/comparison.ll b/tests/input/comparison.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/comparison.ll
@@ -0,0 +1,10 @@
+; ModuleID = 'simple module'
+
+define i1 @main(i32 %x) {
+entry:
+  %x.addr = alloca i32
+  store i32 %x, i32* %x.addr
+  %0 = load i32, i32* %x.addr
+  %1 = icmp ult i32 %0, 1
+  ret i1 %1
+}
diff --git a/tests/input/const.ll b/tests/input/const.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/const.ll
@@ -0,0 +1,100 @@
+; === [ Constants ] ============================================================
+
+; --- [ Integer constant ] -----------------------------------------------------
+
+@g1 = global i32 42
+@g2 = global i32 -42
+
+; --- [ Floating-point constant ] ----------------------------------------------
+
+; Fraction floating-point literal.
+@g3 = global double 42.0
+@g4 = global double +42.0
+@g5 = global double -42.0
+@g6 = global double 42.
+@g7 = global double +42.
+@g8 = global double -42.
+
+; Scientific floating-point literal.
+@g9 = global double 4.2e1
+@g10 = global double 4.2E1
+@g11 = global double 4.2e+1
+@g12 = global double 4.2E+1
+@g13 = global double 420.0e-1
+@g14 = global double 420.0E-1
+@g15 = global double +4.2e1
+@g16 = global double +4.2E1
+@g17 = global double +4.2e+1
+@g18 = global double +4.2E+1
+@g19 = global double +420.0e-1
+@g20 = global double +420.0E-1
+@g21 = global double -4.2e1
+@g22 = global double -4.2E1
+@g23 = global double -4.2e+1
+@g24 = global double -4.2E+1
+@g25 = global double -420.0e-1
+@g26 = global double -420.0E-1
+
+; Hexadecimal floating-point literal.
+@g27 = global double 0x0000000000000000
+;@g28 = global x86_fp80 0xK00000000000000000000
+; TODO: add test case for 0xL floating-point constant.
+;@g29 = global fp128 0xL00000000000000000000000000000000
+; TODO: add test case for 0xM floating-point constant.
+;@g30 = global ppc_fp128 0xM00000000000000000000000000000000
+;@g31 = global half 0xH0000
+
+; --- [ Pointer constant ] -----------------------------------------------------
+
+; Null pointer.
+@g32 = global i32* null
+
+; Global variable.
+@g33 = global i32** @g32
+
+; Function.
+@g34 = global void ()* @f1
+
+; --- [ Vector constant ] ------------------------------------------------------
+
+@g35 = global <1 x i32> <i32 42>
+@g36 = global <2 x i32> <i32 42, i32 11>
+
+; --- [ Array constant ] -------------------------------------------------------
+
+; Array constant.
+@g37 = global [0 x i32] []
+@g38 = global [1 x i32] [i32 42]
+@g39 = global [2 x i32] [i32 42, i32 11]
+
+; Character array.
+@g40 = global [0 x i8] c""
+@g41 = global [1 x i8] c"f"
+@g42 = global [2 x i8] c"fo"
+@g43 = global [3 x i8] c"foo"
+
+; --- [ Struct constant ] ------------------------------------------------------
+
+; Struct constant.
+@g44 = global {} {}
+@g45 = global { i32 } { i32 42 }
+@g46 = global { i32, i32 } { i32 42, i32 42 }
+
+; Nested struct.
+@g47 = global { i32, { i8 } } { i32 42, { i8 } { i8 42 } }
+
+; Packed.
+@g48 = global <{}> <{}>
+@g49 = global <{ i32, i8, i32 }> <{ i32 42, i8 5, i32 11 }>
+
+; --- [ Zero initializer constant ] --------------------------------------------
+
+@g50 = global { i32, i8, { i32, i32 }, i8 } zeroinitializer
+
+; --- [ Undefined value constant ] ---------------------------------------------
+
+@g51 = global i8* undef
+
+define void @f1() {
+	ret void
+}
diff --git a/tests/input/datalayout.ll b/tests/input/datalayout.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/datalayout.ll
@@ -0,0 +1,11 @@
+; ModuleID = 'sample'
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux"
+
+define i32 @foo(i32 %x) {
+entry:
+  %x.addr = alloca i32
+  store i32 %x, i32* %x.addr
+  ret i32 1001
+}
diff --git a/tests/input/debug.ll b/tests/input/debug.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug.ll
@@ -0,0 +1,11 @@
+; ModuleID = 'simple module'
+
+@"%i" = global [3 x i8] c"%i\00"
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+  %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"%i", i32 0, i32 0), i32 42)
+  ret i32 %0
+}
diff --git a/tests/input/debug_metadata_array.ll b/tests/input/debug_metadata_array.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_array.ll
@@ -0,0 +1,36 @@
+define i32 @main() nounwind ssp !dbg !0 {
+entry:
+  %retval = alloca i32, align 4
+  %a = alloca [0 x i32], align 4
+  store i32 0, i32* %retval
+  call void @llvm.dbg.declare(metadata [0 x i32]* %a, metadata !6, metadata !DIExpression()), !dbg !11
+  ret i32 0, !dbg !12
+}
+
+declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!16}
+
+!0 = distinct !DISubprogram(name: "main", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, isOptimized: false, unit: !2, scopeLine: 3, file: !14, scope: !1, type: !3)
+!1 = !DIFile(filename: "array.c", directory: "/private/tmp")
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.0 (trunk 129138)", isOptimized: false, emissionKind: FullDebug, file: !14, enums: !15, retainedTypes: !15, imports:  null)
+!3 = !DISubroutineType(types: !4)
+!4 = !{!5}
+!5 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!6 = !DILocalVariable(name: "a", line: 4, scope: !7, file: !1, type: !8)
+!7 = distinct !DILexicalBlock(line: 3, column: 12, file: !14, scope: !0)
+!8 = !DICompositeType(tag: DW_TAG_array_type, align: 32, file: !14, scope: !2, baseType: !5, elements: !9)
+!9 = !{!10}
+;CHECK: debug_info,
+;CHECK: DW_TAG_subrange_type
+;CHECK-NEXT: DW_AT_type
+;CHECK-NOT: DW_AT_lower_bound
+;CHECK-NOT: DW_AT_upper_bound
+;CHECK-NEXT: End Of Children Mark
+!10 = !DISubrange(count: -1)
+!11 = !DILocation(line: 4, column: 7, scope: !7)
+!12 = !DILocation(line: 5, column: 3, scope: !7)
+!14 = !DIFile(filename: "array.c", directory: "/private/tmp")
+!15 = !{}
+!16 = !{i32 1, !"Debug Info Version", i32 3}
diff --git a/tests/input/debug_metadata_dimodule.ll b/tests/input/debug_metadata_dimodule.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_dimodule.ll
@@ -0,0 +1,16 @@
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx"
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !1, producer: "LLVM version 3.7.0", isOptimized: false, runtimeVersion: 2, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !2, imports: !3)
+!1 = !DIFile(filename: "/llvm/tools/clang/test/Modules/<stdin>", directory: "/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !5, file: !1, line: 5)
+!5 = !DIModule(scope: null, name: "DebugModule", configMacros: "-DMODULES=0", includePath: "/llvm/tools/clang/test/Modules/Inputs", isysroot: "/")
+!6 = !{i32 2, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{!"LLVM version 3.7.0"}
diff --git a/tests/input/debug_metadata_enum.ll b/tests/input/debug_metadata_enum.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_enum.ll
@@ -0,0 +1,47 @@
+source_filename = "test/DebugInfo/Generic/enum.ll"
+
+@a = global i64 0, align 8, !dbg !0
+
+; Function Attrs: nounwind uwtable
+define void @_Z4funcv() #0 !dbg !17 {
+entry:
+  %b = alloca i32, align 4
+  call void @llvm.dbg.declare(metadata i32* %b, metadata !20, metadata !22), !dbg !23
+  store i32 0, i32* %b, align 4, !dbg !23
+  ret void, !dbg !24
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!8}
+!llvm.module.flags = !{!15, !16}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = !DIGlobalVariable(name: "a", scope: null, file: !2, line: 1, type: !3, isLocal: false, isDefinition: true)
+!2 = !DIFile(filename: "enum.cpp", directory: "/tmp")
+!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "e1", file: !2, line: 1, size: 64, align: 64, elements: !4)
+!4 = !{!5, !6, !7}
+!5 = !DIEnumerator(name: "I", value: 0)
+!6 = !DIEnumerator(name: "J", value: 4294967295) ; [ DW_TAG_enumerator ] [I :: 0]
+!7 = !DIEnumerator(name: "K", value: -1152921504606846976) ; [ DW_TAG_enumerator ] [J :: 4294967295]
+!8 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "clang version 3.4 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !9, retainedTypes: !13, globals: !14, imports: !13) ; [ DW_TAG_enumerator ] [K :: 17293822569102704640]
+!9 = !{!3, !10}
+!10 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "e2", file: !2, line: 2, size: 32, align: 32, elements: !11)
+!11 = !{!12}
+!12 = !DIEnumerator(name: "X", value: 0) ; [ DW_TAG_enumerator ] [X :: 0]
+!13 = !{}
+!14 = !{!0}
+!15 = !{i32 2, !"Dwarf Version", i32 3}
+!16 = !{i32 1, !"Debug Info Version", i32 3}
+!17 = distinct !DISubprogram(name: "func", linkageName: "_Z4funcv", scope: !2, file: !2, line: 3, type: !18, isLocal: false, isDefinition: true, scopeLine: 3, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !8, variables: !13)
+!18 = !DISubroutineType(types: !19)
+!19 = !{null}
+!20 = !DILocalVariable(name: "b", scope: !17, file: !2, line: 4, type: !21)
+!21 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!22 = !DIExpression()
+!23 = !DILocation(line: 4, scope: !17)
+!24 = !DILocation(line: 5, scope: !17)
diff --git a/tests/input/debug_metadata_global.ll b/tests/input/debug_metadata_global.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_global.ll
@@ -0,0 +1,26 @@
+source_filename = "test/DebugInfo/Generic/global.ll"
+
+; Function Attrs: nounwind readnone uwtable
+define i32 @main() #0 !dbg !9 {
+entry:
+  ret i32 0, !dbg !12
+}
+
+attributes #0 = { nounwind readnone uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.4 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !2, globals: !3, imports: !2)
+!1 = !DIFile(filename: "global.cpp", directory: "/tmp")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression())
+!5 = !DIGlobalVariable(name: "i", linkageName: "_ZL1i", scope: null, file: !1, line: 1, type: !6, isLocal: true, isDefinition: true)
+!6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!7 = !{i32 2, !"Dwarf Version", i32 3}
+!8 = !{i32 1, !"Debug Info Version", i32 3}
+!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 2, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !2)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!6}
+!12 = !DILocation(line: 4, scope: !9)
diff --git a/tests/input/debug_metadata_macro.ll b/tests/input/debug_metadata_macro.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_macro.ll
@@ -0,0 +1,33 @@
+!llvm.dbg.cu = !{!0, !16, !20}
+!llvm.module.flags = !{!13, !14}
+!llvm.ident = !{!15}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2, macros: !3)
+!1 = !DIFile(filename: "debug-macro.cpp", directory: "/")
+!2 = !{}
+!3 = !{!4, !5}
+!4 = !DIMacro(type: DW_MACINFO_define, line: 0, name: "NameCMD", value: "ValueCMD")
+!5 = !DIMacroFile(line: 0, file: !1, nodes: !6)
+!6 = !{!7, !12}
+!7 = !DIMacroFile(line: 9, file: !8, nodes: !9)
+!8 = !DIFile(filename: "debug-macro.h", directory: "/")
+!9 = !{!10, !11}
+!10 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "NameDef", value: "Value")
+!11 = !DIMacro(type: DW_MACINFO_undef, line: 11, name: "NameUndef")
+!12 = !DIMacro(type: DW_MACINFO_undef, line: 10, name: "NameUndef2")
+
+!13 = !{i32 2, !"Dwarf Version", i32 4}
+!14 = !{i32 1, !"Debug Info Version", i32 3}
+!15 = !{!"clang version 3.5.0 "}
+
+!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: FullDebug, file: !17, enums: !2, retainedTypes: !22, globals: !2, imports: !2, macros: !18)
+!17 = !DIFile(filename: "debug-macro1.cpp", directory: "/")
+!18 = !{!19}
+!19 = !DIMacroFile(line: 0, file: !17, nodes: !2)
+
+!20 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: FullDebug, file: !21, enums: !2, retainedTypes: !24, globals: !2, imports: !2)
+!21 = !DIFile(filename: "debug-macro2.cpp", directory: "/")
+!22 = !{!23}
+!23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!24 = !{!25}
+!25 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
diff --git a/tests/input/debug_metadata_namespace.ll b/tests/input/debug_metadata_namespace.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_namespace.ll
@@ -0,0 +1,164 @@
+@_ZN1A1B1iE = global i32 0, align 4, !dbg !131
+@_ZN1A1B7var_fwdE = global i32 0, align 4, !dbg !132
+@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_debug_info_namespace.cpp, i8* null }]
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @_ZN1A1B2f1Ev() #0 !dbg !10 {
+entry:
+  ret i32 0, !dbg !60
+}
+
+; Function Attrs: nounwind ssp uwtable
+define void @_ZN1A1B2f1Ei(i32) #0 !dbg !14 {
+entry:
+  %.addr = alloca i32, align 4
+  store i32 %0, i32* %.addr, align 4
+  call void @llvm.dbg.declare(metadata i32* %.addr, metadata !61, metadata !62), !dbg !63
+  ret void, !dbg !64
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+define internal void @__cxx_global_var_init() section "__TEXT,__StaticInit,regular,pure_instructions" !dbg !17 {
+entry:
+  %call = call i32 @_ZN1A1B2f1Ev(), !dbg !65
+  store i32 %call, i32* @_ZN1A1B1iE, align 4, !dbg !65
+  ret void, !dbg !65
+}
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @_Z4funcb(i1 zeroext %b) #0 !dbg !21 {
+entry:
+  %retval = alloca i32, align 4
+  %b.addr = alloca i8, align 1
+  %frombool = zext i1 %b to i8
+  store i8 %frombool, i8* %b.addr, align 1
+  call void @llvm.dbg.declare(metadata i8* %b.addr, metadata !66, metadata !62), !dbg !67
+  %0 = load i8, i8* %b.addr, align 1, !dbg !68
+  %tobool = trunc i8 %0 to i1, !dbg !68
+  br i1 %tobool, label %if.then, label %if.end, !dbg !68
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, i32* @_ZN1A1B1iE, align 4, !dbg !69
+  store i32 %1, i32* %retval, !dbg !69
+  br label %return, !dbg !69
+
+if.end:                                           ; preds = %entry
+  %2 = load i32, i32* @_ZN1A1B1iE, align 4, !dbg !70
+  %3 = load i32, i32* @_ZN1A1B1iE, align 4, !dbg !70
+  %add = add nsw i32 %2, %3, !dbg !70
+  %4 = load i32, i32* @_ZN1A1B1iE, align 4, !dbg !70
+  %add1 = add nsw i32 %add, %4, !dbg !70
+  store i32 %add1, i32* %retval, !dbg !70
+  br label %return, !dbg !70
+
+return:                                           ; preds = %if.end, %if.then
+  %5 = load i32, i32* %retval, !dbg !71
+  ret i32 %5, !dbg !71
+}
+
+define internal void @__cxx_global_var_init1() section "__TEXT,__StaticInit,regular,pure_instructions" !dbg !25 {
+entry:
+  %0 = load i32, i32* @_ZN1A1B1iE, align 4, !dbg !72
+  store i32 %0, i32* @_ZN1A1B7var_fwdE, align 4, !dbg !72
+  ret void, !dbg !72
+}
+
+; Function Attrs: nounwind ssp uwtable
+define void @_ZN1A1B8func_fwdEv() #0 !dbg !26 {
+entry:
+  ret void, !dbg !73
+}
+
+define internal void @_GLOBAL__sub_I_debug_info_namespace.cpp() section "__TEXT,__StaticInit,regular,pure_instructions" {
+entry:
+  call void @__cxx_global_var_init(), !dbg !74
+  call void @__cxx_global_var_init1(), !dbg !74
+  ret void, !dbg !74
+}
+
+attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!57, !58}
+!llvm.ident = !{!59}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !3, globals: !30, imports: !33)
+!1 = !DIFile(filename: "debug-info-namespace.cpp", directory: "/tmp")
+!2 = !{}
+!3 = !{!4, !8}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", line: 5, flags: DIFlagFwdDecl, file: !5, scope: !6, identifier: "_ZTSN1A1B3fooE")
+!5 = !DIFile(filename: "foo.cpp", directory: "/tmp")
+!6 = !DINamespace(name: "B", scope: !7)
+!7 = !DINamespace(name: "A", scope: null)
+!8 = !DICompositeType(tag: DW_TAG_structure_type, name: "bar", line: 6, size: 8, align: 8, file: !5, scope: !6, elements: !2, identifier: "_ZTSN1A1B3barE")
+!10 = distinct !DISubprogram(name: "f1", linkageName: "_ZN1A1B2f1Ev", line: 3, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !5, scope: !6, type: !11, variables: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!14 = distinct !DISubprogram(name: "f1", linkageName: "_ZN1A1B2f1Ei", line: 4, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 4, file: !5, scope: !6, type: !15, variables: !2)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null, !13}
+!17 = distinct !DISubprogram(name: "__cxx_global_var_init", line: 20, isLocal: true, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 20, file: !5, scope: !18, type: !19, variables: !2)
+!18 = !DIFile(filename: "foo.cpp", directory: "/tmp")
+!19 = !DISubroutineType(types: !20)
+!20 = !{null}
+!21 = distinct !DISubprogram(name: "func", linkageName: "_Z4funcb", line: 21, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 21, file: !5, scope: !18, type: !22, variables: !2)
+!22 = !DISubroutineType(types: !23)
+!23 = !{!13, !24}
+!24 = !DIBasicType(tag: DW_TAG_base_type, name: "bool", size: 8, align: 8, encoding: DW_ATE_boolean)
+!25 = distinct !DISubprogram(name: "__cxx_global_var_init1", line: 44, isLocal: true, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 44, file: !5, scope: !18, type: !19, variables: !2)
+!26 = distinct !DISubprogram(name: "func_fwd", linkageName: "_ZN1A1B8func_fwdEv", line: 47, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 47, file: !5, scope: !6, type: !19, variables: !2)
+!27 = distinct !DISubprogram(name: "", linkageName: "_GLOBAL__sub_I_debug_info_namespace.cpp", isLocal: true, isDefinition: true, flags: DIFlagArtificial, isOptimized: false, unit: !0, file: !1, scope: !28, type: !29, variables: !2)
+!28 = !DIFile(filename: "debug-info-namespace.cpp", directory: "/tmp")
+!29 = !DISubroutineType(types: !2)
+!30 = !{!131, !132}
+!31 = !DIGlobalVariable(name: "i", linkageName: "_ZN1A1B1iE", line: 20, isLocal: false, isDefinition: true, scope: !6, file: !18, type: !13)
+!32 = !DIGlobalVariable(name: "var_fwd", linkageName: "_ZN1A1B7var_fwdE", line: 44, isLocal: false, isDefinition: true, scope: !6, file: !18, type: !13)
+!33 = !{!34, !35, !36, !37, !40, !41, !42, !43, !44, !45, !47, !48, !49, !51, !54, !55, !56}
+!34 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 15, scope: !7, entity: !6)
+!35 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 18, scope: !0, entity: !7)
+!36 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 19, name: "E", scope: !0, entity: !7)
+!37 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 23, scope: !38, entity: !6)
+!38 = distinct !DILexicalBlock(line: 22, column: 10, file: !5, scope: !39)
+!39 = distinct !DILexicalBlock(line: 22, column: 7, file: !5, scope: !21)
+!40 = !DIImportedEntity(tag: DW_TAG_imported_module, file: !5, line: 26, scope: !21, entity: !7)
+!41 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 27, scope: !21, entity: !4)
+!42 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 28, scope: !21, entity: !8)
+!43 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 29, scope: !21, entity: !14)
+!44 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 30, scope: !21, entity: !31)
+!45 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 31, scope: !21, entity: !46)
+!46 = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", line: 7, file: !5, scope: !6, baseType: !8)
+!47 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 32, name: "X", scope: !21, entity: !7)
+!48 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 33, name: "Y", scope: !21, entity: !47)
+!49 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 34, scope: !21, entity: !50)
+!50 = !DIGlobalVariable(name: "var_decl", linkageName: "_ZN1A1B8var_declE", line: 8, isLocal: false, isDefinition: false, scope: !6, file: !18, type: !13)
+!51 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 35, scope: !21, entity: !52)
+!52 = !DISubprogram(name: "func_decl", linkageName: "_ZN1A1B9func_declEv", line: 9, isLocal: false, isDefinition: false, flags: DIFlagPrototyped, isOptimized: false, file: !5, scope: !6, type: !19, variables: !53)
+!53 = !{} ; previously: invalid DW_TAG_base_type
+!54 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 36, scope: !21, entity: !32)
+!55 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 37, scope: !21, entity: !26)
+!56 = !DIImportedEntity(tag: DW_TAG_imported_declaration, file: !5, line: 42, scope: !7, entity: !31)
+!57 = !{i32 2, !"Dwarf Version", i32 2}
+!58 = !{i32 2, !"Debug Info Version", i32 3}
+!59 = !{!"clang version 3.6.0 "}
+!60 = !DILocation(line: 3, column: 12, scope: !10)
+!61 = !DILocalVariable(name: "", line: 4, arg: 1, scope: !14, file: !18, type: !13)
+!62 = !DIExpression()
+!63 = !DILocation(line: 4, column: 12, scope: !14)
+!64 = !DILocation(line: 4, column: 16, scope: !14)
+!65 = !DILocation(line: 20, column: 12, scope: !17)
+!66 = !DILocalVariable(name: "b", line: 21, arg: 1, scope: !21, file: !18, type: !24)
+!67 = !DILocation(line: 21, column: 15, scope: !21)
+!68 = !DILocation(line: 22, column: 7, scope: !21)
+!69 = !DILocation(line: 24, column: 5, scope: !38)
+!70 = !DILocation(line: 38, column: 3, scope: !21)
+!71 = !DILocation(line: 39, column: 1, scope: !21)
+!72 = !DILocation(line: 44, column: 15, scope: !25)
+!73 = !DILocation(line: 47, column: 21, scope: !26)
+!74 = !DILocation(line: 0, scope: !75)
+!75 = !DILexicalBlockFile(discriminator: 0, file: !5, scope: !27)
+!131 = !DIGlobalVariableExpression(var: !31, expr: !DIExpression())
+!132 = !DIGlobalVariableExpression(var: !32, expr: !DIExpression())
diff --git a/tests/input/debug_metadata_objcproperty.ll b/tests/input/debug_metadata_objcproperty.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_objcproperty.ll
@@ -0,0 +1,12 @@
+!named = !{!0, !1, !2, !3, !4, !5}
+
+!0 = distinct !{}
+!1 = !DIFile(filename: "path/to/file", directory: "/path/to/dir")
+!2 = !DICompositeType(tag: DW_TAG_structure_type, name: "Object")
+
+!3 = !DIObjCProperty(name: "foo", file: !1, line: 7, setter: "setFoo",
+                     getter: "getFoo", attributes: 7, type: !2)
+
+!4 = !DIObjCProperty(name: "", file: null, line: 0, setter: "", getter: "",
+                     attributes: 0, type: null)
+!5 = !DIObjCProperty()
diff --git a/tests/input/debug_metadata_qualifiers.ll b/tests/input/debug_metadata_qualifiers.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_qualifiers.ll
@@ -0,0 +1,63 @@
+%class.A = type { i8 }
+
+; Function Attrs: nounwind
+define void @_Z1gv() #0 !dbg !17 {
+  %a = alloca %class.A, align 1
+  %pl = alloca { i64, i64 }, align 8
+  %pr = alloca { i64, i64 }, align 8
+  call void @llvm.dbg.declare(metadata %class.A* %a, metadata !24, metadata !DIExpression()), !dbg !25
+  call void @llvm.dbg.declare(metadata { i64, i64 }* %pl, metadata !26, metadata !DIExpression()), !dbg !31
+  store { i64, i64 } { i64 ptrtoint (void (%class.A*)* @_ZNKR1A1lEv to i64), i64 0 }, { i64, i64 }* %pl, align 8, !dbg !31
+  call void @llvm.dbg.declare(metadata { i64, i64 }* %pr, metadata !32, metadata !DIExpression()), !dbg !35
+  store { i64, i64 } { i64 ptrtoint (void (%class.A*)* @_ZNKO1A1rEv to i64), i64 0 }, { i64, i64 }* %pr, align 8, !dbg !35
+  ret void, !dbg !36
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+declare void @_ZNKR1A1lEv(%class.A*)
+
+declare void @_ZNKO1A1rEv(%class.A*)
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!21, !22}
+!llvm.ident = !{!23}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "debug-info-qualifiers.cpp", directory: "")
+!2 = !{}
+!3 = !{!4}
+!4 = !DICompositeType(tag: DW_TAG_class_type, name: "A", line: 2, size: 8, align: 8, file: !5, elements: !6, identifier: "_ZTS1A")
+!5 = !DIFile(filename: "debug-info-qualifiers.cpp", directory: "")
+!6 = !{!7, !13}
+!7 = !DISubprogram(name: "l", linkageName: "_ZNKR1A1lEv", line: 5, isLocal: false, isDefinition: false, virtualIndex: 6, flags: DIFlagPrototyped | DIFlagLValueReference, isOptimized: false, scopeLine: 5, file: !5, scope: !4, type: !8)
+!8 = !DISubroutineType(flags: DIFlagLValueReference, types: !9)
+!9 = !{null, !10}
+!10 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer, baseType: !11)
+!11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !4)
+!13 = !DISubprogram(name: "r", linkageName: "_ZNKO1A1rEv", line: 7, isLocal: false, isDefinition: false, virtualIndex: 6, flags: DIFlagObjectPointer | DIFlagRValueReference, isOptimized: false, scopeLine: 7, file: !5, scope: !4, type: !14)
+!14 = !DISubroutineType(flags: DIFlagRValueReference, types: !9)
+!17 = distinct !DISubprogram(name: "g", linkageName: "_Z1gv", line: 10, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 10, file: !5, scope: !18, type: !19, variables: !2)
+!18 = !DIFile(filename: "debug-info-qualifiers.cpp", directory: "")
+!19 = !DISubroutineType(types: !20)
+!20 = !{null}
+!21 = !{i32 2, !"Dwarf Version", i32 4}
+!22 = !{i32 1, !"Debug Info Version", i32 3}
+!23 = !{!"clang version 3.5 "}
+!24 = !DILocalVariable(name: "a", line: 11, scope: !17, file: !18, type: !4)
+!25 = !DILocation(line: 11, scope: !17)
+!26 = !DILocalVariable(name: "pl", line: 16, scope: !17, file: !18, type: !27)
+!27 = !DIDerivedType(tag: DW_TAG_ptr_to_member_type, baseType: !28, extraData: !4)
+!28 = !DISubroutineType(flags: DIFlagLValueReference, types: !29)
+!29 = !{null, !30}
+!30 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer, baseType: !4)
+!31 = !DILocation(line: 16, scope: !17)
+!32 = !DILocalVariable(name: "pr", line: 21, scope: !17, file: !18, type: !33)
+!33 = !DIDerivedType(tag: DW_TAG_ptr_to_member_type, baseType: !34, extraData: !4)
+!34 = !DISubroutineType(flags: DIFlagRValueReference, types: !29)
+!35 = !DILocation(line: 21, scope: !17)
+!36 = !DILocation(line: 22, scope: !17)
diff --git a/tests/input/debug_metadata_templateparameter.ll b/tests/input/debug_metadata_templateparameter.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_templateparameter.ll
@@ -0,0 +1,11 @@
+!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
+!0 = distinct !{}
+!1 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!2 = !DITemplateTypeParameter(name: "Ty", type: !1)
+!3 = !DITemplateTypeParameter(type: !1)
+!4 = !DITemplateTypeParameter(name: "", type: !1)
+!5 = !DITemplateValueParameter(name: "V", type: !1, value: i32 7)
+!6 = !DITemplateValueParameter(type: !1, value: i32 7)
+!7 = !DITemplateValueParameter(tag: DW_TAG_template_value_parameter,
+                               name: "", type: !1, value: i32 7)
+!8 = !DITemplateValueParameter(tag: DW_TAG_GNU_template_template_param, name: "param", type: !1, value: !"template")
diff --git a/tests/input/debug_metadata_tu_composite.ll b/tests/input/debug_metadata_tu_composite.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_tu_composite.ll
@@ -0,0 +1,106 @@
+%struct.C = type { i32 (...)** }
+%struct.bar = type { i8 }
+%"struct.D::Nested" = type { i8 }
+%"struct.D::Nested2" = type { i8 }
+%"struct.D::virt" = type { %struct.bar* }
+
+@_ZTV1C = unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1C to i8*), i8* bitcast (void (%struct.C*)* @_ZN1C3fooEv to i8*)]
+@_ZTVN10__cxxabiv117__class_type_infoE = external global i8*
+@_ZTS1C = constant [3 x i8] c"1C\00"
+@_ZTI1C = unnamed_addr constant { i8*, i8* } { i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0) }
+
+; Function Attrs: nounwind ssp uwtable
+define void @_ZN1C3fooEv(%struct.C* %this) unnamed_addr #0 align 2 !dbg !31 {
+entry:
+  %this.addr = alloca %struct.C*, align 8
+  store %struct.C* %this, %struct.C** %this.addr, align 8
+  call void @llvm.dbg.declare(metadata %struct.C** %this.addr, metadata !36, metadata !DIExpression()), !dbg !38
+  %this1 = load %struct.C*, %struct.C** %this.addr
+  ret void, !dbg !39
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind ssp uwtable
+define void @_Z4testv() #0 !dbg !32 {
+entry:
+  %B = alloca %struct.bar, align 1
+  %A = alloca [3 x %struct.bar], align 1
+  %B2 = alloca %struct.bar, align 1
+  %e = alloca %"struct.D::Nested", align 1
+  %p = alloca %"struct.D::Nested2"*, align 8
+  %t = alloca %"struct.D::virt", align 8
+  call void @llvm.dbg.declare(metadata %struct.bar* %B, metadata !40, metadata !DIExpression()), !dbg !42
+  call void @llvm.dbg.declare(metadata [3 x %struct.bar]* %A, metadata !43, metadata !DIExpression()), !dbg !47
+  call void @llvm.dbg.declare(metadata %struct.bar* %B2, metadata !48, metadata !DIExpression()), !dbg !50
+  call void @llvm.dbg.declare(metadata %"struct.D::Nested"* %e, metadata !51, metadata !DIExpression()), !dbg !52
+  call void @llvm.dbg.declare(metadata %"struct.D::Nested2"** %p, metadata !53, metadata !DIExpression()), !dbg !55
+  call void @llvm.dbg.declare(metadata %"struct.D::virt"* %t, metadata !56, metadata !DIExpression()), !dbg !57
+  ret void, !dbg !58
+}
+
+attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!35, !59}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.4", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "tmp.cpp", directory: ".")
+!2 = !{}
+!3 = !{!4, !18, !19, !22, !23, !24}
+!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "C", line: 1, file: !1, elements: !5, vtableHolder: !4, identifier: "_ZTS1C")
+!5 = !{!6, !13}
+!6 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$C", flags: DIFlagArtificial, file: !1, scope: !7, baseType: !8)
+!7 = !DIFile(filename: "tmp.cpp", directory: ".")
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, baseType: !9)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", size: 64, baseType: !10)
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12}
+!12 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!13 = !DISubprogram(name: "foo", linkageName: "_ZN1C3fooEv", line: 2, isLocal: false, isDefinition: false, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 2, file: !1, scope: !4, type: !14, containingType: !4)
+!14 = !DISubroutineType(types: !15)
+!15 = !{null, !16}
+!16 = !DIDerivedType(tag: DW_TAG_pointer_type, flags: DIFlagArtificial | DIFlagObjectPointer, baseType: !4)
+!18 = !DICompositeType(tag: DW_TAG_structure_type, name: "bar", line: 7, size: 8, align: 8, file: !1, elements: !2, identifier: "_ZTS3bar")
+!19 = !DICompositeType(tag: DW_TAG_structure_type, name: "D", line: 9, size: 8, align: 8, file: !1, elements: !20, identifier: "_ZTS1D")
+!20 = !{!21}
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "a", line: 11, flags: DIFlagStaticMember, file: !1, scope: !19, baseType: !12)
+!22 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", line: 12, size: 8, align: 8, file: !1, scope: !19, elements: !2, identifier: "_ZTSN1D6NestedE")
+!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested2", line: 13, flags: DIFlagFwdDecl, file: !1, scope: !19, identifier: "_ZTSN1D7Nested2E")
+!24 = !DICompositeType(tag: DW_TAG_structure_type, name: "virt<bar>", line: 15, file: !1, scope: !19, elements: !25, templateParams: !28, identifier: "_ZTSN1D4virtI3barEE")
+!25 = !{!26}
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "values", line: 16, size: 64, align: 64, file: !1, scope: !24, baseType: !27)
+!27 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !18)
+!28 = !{!29}
+!29 = !DITemplateTypeParameter(name: "T", type: !18)
+!31 = distinct !DISubprogram(name: "foo", linkageName: "_ZN1C3fooEv", line: 4, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 4, file: !1, scope: null, type: !14, declaration: !13, variables: !2)
+!32 = distinct !DISubprogram(name: "test", linkageName: "_Z4testv", line: 20, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 20, file: !1, scope: !7, type: !33, variables: !2)
+!33 = !DISubroutineType(types: !34)
+!34 = !{null}
+!35 = !{i32 2, !"Dwarf Version", i32 2}
+!36 = !DILocalVariable(name: "this", arg: 1, flags: DIFlagArtificial | DIFlagObjectPointer, scope: !31, type: !37)
+!37 = !DIDerivedType(tag: DW_TAG_pointer_type, size: 64, align: 64, baseType: !4)
+!38 = !DILocation(line: 0, scope: !31)
+!39 = !DILocation(line: 5, scope: !31)
+!40 = !DILocalVariable(name: "B", line: 21, scope: !32, file: !7, type: !41)
+!41 = !DIDerivedType(tag: DW_TAG_typedef, name: "baz", line: 8, file: !1, baseType: !18)
+!42 = !DILocation(line: 21, scope: !32)
+!43 = !DILocalVariable(name: "A", line: 22, scope: !32, file: !7, type: !44)
+!44 = !DICompositeType(tag: DW_TAG_array_type, size: 24, align: 8, baseType: !18, elements: !45)
+!45 = !{!46}
+!46 = !DISubrange(count: 3)
+!47 = !DILocation(line: 22, scope: !32)
+!48 = !DILocalVariable(name: "B2", line: 23, scope: !32, file: !7, type: !49)
+!49 = !DIDerivedType(tag: DW_TAG_typedef, name: "baz2", line: 10, file: !1, scope: !19, baseType: !18)
+!50 = !DILocation(line: 23, scope: !32)
+!51 = !DILocalVariable(name: "e", line: 24, scope: !32, file: !7, type: !22)
+!52 = !DILocation(line: 24, scope: !32)
+!53 = !DILocalVariable(name: "p", line: 25, scope: !32, file: !7, type: !54)
+!54 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23)
+!55 = !DILocation(line: 25, scope: !32)
+!56 = !DILocalVariable(name: "t", line: 26, scope: !32, file: !7, type: !24)
+!57 = !DILocation(line: 26, scope: !32)
+!58 = !DILocation(line: 27, scope: !32)
+!59 = !{i32 1, !"Debug Info Version", i32 3}
diff --git a/tests/input/debug_metadata_union.ll b/tests/input/debug_metadata_union.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/debug_metadata_union.ll
@@ -0,0 +1,50 @@
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.10.0"
+
+%union.mfi_evt = type { %struct.anon }
+%struct.anon = type { i32 }
+
+; Function Attrs: nounwind readnone ssp uwtable
+define i32 @mfi_aen_setup() #0 !dbg !4 {
+entry:
+  tail call void @llvm.dbg.declare(metadata %union.mfi_evt* undef, metadata !16, metadata !21), !dbg !22
+  tail call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !21), !dbg !22
+  ret i32 undef, !dbg !23
+}
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: nounwind readnone
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { nounwind readnone ssp uwtable }
+attributes #1 = { nounwind readnone }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!17, !18, !19}
+!llvm.ident = !{!20}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.7.0 (trunk 226915) (llvm/trunk 226905)", isOptimized: true, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "union.c", directory: "")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "mfi_aen_setup", line: 5, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, scopeLine: 5, file: !1, scope: !5, type: !6, variables: !15)
+!5 = !DIFile(filename: "union.c", directory: "")
+!6 = !DISubroutineType(types: !7)
+!7 = !{!8}
+!8 = !DICompositeType(tag: DW_TAG_union_type, name: "mfi_evt", line: 1, size: 32, align: 32, file: !1, elements: !9)
+!9 = !{!10}
+!10 = !DIDerivedType(tag: DW_TAG_member, name: "members", line: 4, size: 32, align: 32, file: !1, scope: !8, baseType: !11)
+!11 = !DICompositeType(tag: DW_TAG_structure_type, line: 2, size: 32, align: 32, file: !1, scope: !8, elements: !12)
+!12 = !{!13}
+!13 = !DIDerivedType(tag: DW_TAG_member, name: "reserved", line: 3, size: 32, align: 32, file: !1, scope: !11, baseType: !14)
+!14 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+!15 = !{!16}
+!16 = !DILocalVariable(name: "a", line: 6, scope: !4, file: !5, type: !8)
+!17 = !{i32 2, !"Dwarf Version", i32 2}
+!18 = !{i32 2, !"Debug Info Version", i32 3}
+!19 = !{i32 1, !"PIC Level", i32 2}
+!20 = !{!"clang version 3.7.0 (trunk 226915) (llvm/trunk 226905)"}
+!21 = !DIExpression()
+!22 = !DILocation(line: 6, column: 17, scope: !4)
+!23 = !DILocation(line: 8, column: 1, scope: !4)
diff --git a/tests/input/empty.ll b/tests/input/empty.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/empty.ll
diff --git a/tests/input/eval.ll b/tests/input/eval.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/eval.ll
@@ -0,0 +1,39 @@
+@format = constant [6 x i8] c"%08X\0A\00"
+
+define i32 @add(i32 %a, i32 %b) {
+	%result = add i32 %a, %b
+	ret i32 %result
+}
+
+define i32 @sub(i32 %a, i32 %b) {
+	%result = sub i32 %a, %b
+	ret i32 %result
+}
+
+define i32 @f(i32 %a, i32 %b) {
+	%tmp1 = add i32 %a, %b
+	%tmp2 = sub i32 %tmp1, 1
+	%tmp3 = mul i32 %tmp2, 12345678
+	%tmp4 = udiv i32 %tmp3, 2
+	%tmp5 = sdiv i32 %tmp4, 3
+	%tmp6 = urem i32 %tmp5, 14594
+	%tmp7 = srem i32 %tmp6, 1000
+	%tmp8 = shl i32 %tmp7, 1
+	%tmp9 = lshr i32 %tmp8, 2
+	%tmp10 = mul i32 %tmp9, -1
+	%tmp11 = ashr i32 %tmp10, 2
+	%tmp12 = and i32 %tmp11, 249  ; 0b11111001
+	%tmp13 = or i32 %tmp12, 4     ; 0b00000100
+	%result = xor i32 %tmp13, 255 ; 0b11111111
+	call i32(i8*, ...) @printf(i8* getelementptr ([6 x i8], [6 x i8]* @format, i32 0, i32 0), i32 %result)
+	ret i32 %result
+}
+
+define i32 @main() {
+	%tmp1 = call i32 @add(i32 -1, i32 3)
+	%tmp2 = call i32 @sub(i32 13, i32 5)
+	%result = call i32 @f(i32 %tmp1, i32 %tmp2)
+	ret i32 %result
+}
+
+declare i32 @printf(i8*, ...)
diff --git a/tests/input/expr_aggregate.ll b/tests/input/expr_aggregate.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_aggregate.ll
@@ -0,0 +1,25 @@
+; --- [ Aggregate expressions ] ------------------------------------------------
+
+; ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @extractvalue_1() {
+	; Plain expression.
+	ret i32 extractvalue ({ i8, i32 } { i8 21, i32 42 }, 1)
+}
+
+define i32 @extractvalue_2() {
+	; Nested struct and array operand.
+	ret i32 extractvalue ({ i32, { [2 x i32], i8 } } { i32 0, { [2 x i32], i8 } { [2 x i32] [i32 100, i32 42], i8 11 } }, 1, 0, 1)
+}
+
+; ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define { i32, i32 } @insertvalue_1() {
+	; Plain expression.
+	ret { i32, i32 } insertvalue ({ i32, i32 } { i32 21, i32 42 }, i32 42, 0)
+}
+
+define { i32, { [2 x i32], i32 } } @insertvalue_2() {
+	; Nested struct and array operand.
+	ret { i32, { [2 x i32], i32 } } insertvalue ({ i32, { [2 x i32], i32 } } { i32 42, { [2 x i32], i32 } { [2 x i32] [i32 100, i32 42], i32 42 } }, i32 42, 1, 0, 0)
+}
diff --git a/tests/input/expr_binary.ll b/tests/input/expr_binary.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_binary.ll
@@ -0,0 +1,73 @@
+; --- [ Binary expressions ] ---------------------------------------------------
+
+; ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @add_1() {
+	ret i32 add (i32 30, i32 12)
+}
+
+; ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fadd_1() {
+	ret double fadd (double 30.0, double 12.0)
+}
+
+; ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sub_1() {
+	ret i32 sub (i32 50, i32 8)
+}
+
+; ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fsub_1() {
+	ret double fsub (double 50.0, double 8.0)
+}
+
+; ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @mul_1() {
+	ret i32 mul (i32 21, i32 2)
+}
+
+; ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fmul_1() {
+	ret double fmul (double 21.0, double 2.0)
+}
+
+; ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @udiv_1() {
+	ret i32 udiv (i32 84, i32 2)
+}
+
+; ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sdiv_1() {
+	ret i32 sdiv (i32 -84, i32 -2)
+}
+
+; ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fdiv_1() {
+	ret double fdiv (double 84.0, double 2.0)
+}
+
+; ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @urem_1() {
+	ret i32 urem (i32 85, i32 43)
+}
+
+; ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @srem_1() {
+	ret i32 srem (i32 85, i32 -43)
+}
+
+; ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @frem_1() {
+	ret double frem (double 85.0, double 43.0)
+}
diff --git a/tests/input/expr_bitwise.ll b/tests/input/expr_bitwise.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_bitwise.ll
@@ -0,0 +1,37 @@
+; --- [ Bitwise expressions ] --------------------------------------------------
+
+; ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @shl_1() {
+	ret i32 shl (i32 21, i32 1)
+}
+
+; ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @lshr_1() {
+	ret i32 lshr (i32 84, i32 1)
+}
+
+; ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @ashr_1() {
+	ret i32 ashr (i32 84, i32 1)
+}
+
+; ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @and_1() {
+	ret i32 and (i32 58, i32 239)
+}
+
+; ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @or_1() {
+	ret i32 or (i32 10, i32 32)
+}
+
+; ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @xor_1() {
+	ret i32 xor (i32 255, i32 213)
+}
diff --git a/tests/input/expr_conversion.ll b/tests/input/expr_conversion.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_conversion.ll
@@ -0,0 +1,108 @@
+; --- [ Conversion expressions ] -----------------------------------------------
+
+@x = constant i8 0
+
+; ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8 @trunc_1() {
+	; Plain expression.
+	ret i8 trunc (i32 298 to i8)
+}
+
+; ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @zext_1() {
+	; Plain expression.
+	ret i32 zext (i8 42 to i32)
+}
+
+; ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sext_1() {
+	; Plain expression.
+	ret i32 sext (i8 -42 to i32)
+}
+
+; ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define float @fptrunc_1() {
+	; Plain expression.
+	ret float fptrunc (double 42.0 to float)
+}
+
+; ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fpext_1() {
+	; Plain expression.
+	ret double fpext (float 42.0 to double)
+}
+
+; ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @fptoui_1() {
+	; Plain expression.
+	ret i32 fptoui (double 42.0 to i32)
+}
+
+; ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @fptosi_1() {
+	; Plain expression.
+	ret i32 fptosi (double -42.0 to i32)
+}
+
+; ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @uitofp_1() {
+	; Plain expression.
+	ret double uitofp (i32 42 to double)
+}
+
+; ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @sitofp_1() {
+	; Plain expression.
+	ret double sitofp (i32 -42 to double)
+}
+
+; ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i64 @ptrtoint_1() {
+	; Plain expression.
+	ret i64 ptrtoint (i8* null to i64)
+}
+
+define i64 @ptrtoint_2() {
+	; Local operand.
+	ret i64 ptrtoint (i8* @x to i64)
+}
+
+define void @f() {
+	ret void
+}
+
+define i64 @ptrtoint_3() {
+	; Global operand.
+	ret i64 ptrtoint (void ()* @f to i64)
+}
+
+; ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8* @inttoptr_1() {
+	; Plain expression.
+	ret i8* inttoptr (i32 0 to i8*)
+}
+
+; ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <4 x i8> @bitcast_1() {
+	; Plain expression.
+	ret <4 x i8> bitcast (i32 707406378 to <4 x i8>)
+}
+
+; ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8 addrspace(2)* @addrspacecast_1() {
+	; Plain expression.
+	ret i8 addrspace(2)* addrspacecast (i8 addrspace(1)* null to i8 addrspace(2)*)
+}
diff --git a/tests/input/expr_memory.ll b/tests/input/expr_memory.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_memory.ll
@@ -0,0 +1,22 @@
+; --- [ Memory expressions ] ---------------------------------------------------
+
+@x = constant i32 42
+
+@y = constant { i32, { [2 x i32], i8 } } zeroinitializer
+
+; ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32* @getelementptr_1() {
+	; Plain expression.
+	ret i32* getelementptr (i32, i32* @x)
+}
+
+define i32* @getelementptr_2() {
+	; Indices.
+	ret i32* getelementptr ({ i32, { [2 x i32], i8 } }, { i32, { [2 x i32], i8 } }* @y, i32 0, i32 1, i32 0, i32 1)
+}
+
+define i32* @getelementptr_3() {
+	; Inbounds.
+	ret i32* getelementptr inbounds (i32, i32* @x)
+}
diff --git a/tests/input/expr_other.ll b/tests/input/expr_other.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_other.ll
@@ -0,0 +1,167 @@
+; --- [ Other expressions ] ----------------------------------------------------
+
+; ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i1 @icmp_1() {
+	; Plain expression.
+	ret i1 icmp ne (i32 42, i32 5)
+}
+
+define <2 x i1> @icmp_2() {
+	; Vector operands.
+	ret <2 x i1> icmp eq (<2 x i32> <i32 42, i32 11>, <2 x i32> <i32 42, i32 22>)
+}
+
+define i1 @icmp_3() {
+	; Predicates.
+	ret i1 icmp eq (i32 10, i32 15)
+}
+
+define i1 @icmp_4() {
+	; Predicates.
+	ret i1 icmp ne (i32 10, i32 15)
+}
+
+define i1 @icmp_5() {
+	; Predicates.
+	ret i1 icmp ugt (i32 10, i32 15)
+}
+
+define i1 @icmp_6() {
+	; Predicates.
+	ret i1 icmp uge (i32 10, i32 15)
+}
+
+define i1 @icmp_7() {
+	; Predicates.
+	ret i1 icmp ult (i32 10, i32 15)
+}
+
+define i1 @icmp_8() {
+	; Predicates.
+	ret i1 icmp ule (i32 10, i32 15)
+}
+
+define i1 @icmp_9() {
+	; Predicates.
+	ret i1 icmp sgt (i32 10, i32 15)
+}
+
+define i1 @icmp_10() {
+	; Predicates.
+	ret i1 icmp sge (i32 10, i32 15)
+}
+
+define i1 @icmp_11() {
+	; Predicates.
+	ret i1 icmp slt (i32 10, i32 15)
+}
+
+define i1 @icmp_12() {
+	; Predicates.
+	ret i1 icmp sle (i32 10, i32 15)
+}
+
+; ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i1 @fcmp_1() {
+	; Plain expression.
+	ret i1 fcmp one (double 42.0, double 5.0)
+}
+
+define <2 x i1> @fcmp_2() {
+	; Vector operands.
+	ret <2 x i1> fcmp oeq (<2 x double> <double 42.0, double 11.0>, <2 x double> <double 42.0, double 22.0>)
+}
+
+define i1 @fcmp_3() {
+	; Predicates.
+	ret i1 fcmp false (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_4() {
+	; Predicates.
+	ret i1 fcmp oeq (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_5() {
+	; Predicates.
+	ret i1 fcmp ogt (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_6() {
+	; Predicates.
+	ret i1 fcmp oge (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_7() {
+	; Predicates.
+	ret i1 fcmp olt (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_8() {
+	; Predicates.
+	ret i1 fcmp ole (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_9() {
+	; Predicates.
+	ret i1 fcmp one (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_10() {
+	; Predicates.
+	ret i1 fcmp ord (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_11() {
+	; Predicates.
+	ret i1 fcmp ueq (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_12() {
+	; Predicates.
+	ret i1 fcmp ugt (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_13() {
+	; Predicates.
+	ret i1 fcmp uge (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_14() {
+	; Predicates.
+	ret i1 fcmp ult (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_15() {
+	; Predicates.
+	ret i1 fcmp ule (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_16() {
+	; Predicates.
+	ret i1 fcmp une (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_17() {
+	; Predicates.
+	ret i1 fcmp uno (double 10.0, double 15.0)
+}
+
+define i1 @fcmp_18() {
+	; Predicates.
+	ret i1 fcmp true (double 10.0, double 15.0)
+}
+
+; ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @select_1() {
+	; Plain expression.
+	ret i32 select (i1 true, i32 42, i32 37)
+}
+
+define <2 x i32> @select_2() {
+	; Vector operands.
+	ret <2 x i32> select (i1 false, <2 x i32> <i32 42, i32 37>, <2 x i32> <i32 11, i32 22>)
+}
diff --git a/tests/input/expr_vector.ll b/tests/input/expr_vector.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/expr_vector.ll
@@ -0,0 +1,19 @@
+; --- [ Vector expressions ] ---------------------------------------------------
+
+; ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @extractelement_1() {
+	ret i32 extractelement (<2 x i32> <i32 21, i32 42>, i32 1)
+}
+
+; ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <2 x i32> @insertelement_1() {
+	ret <2 x i32> insertelement (<2 x i32> <i32 21, i32 42>, i32 42, i32 0)
+}
+
+; ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <2 x i32> @shufflevector_1() {
+	ret <2 x i32> shufflevector (<2 x i32> <i32 21, i32 42>, <2 x i32> <i32 42, i32 84>, <2 x i32> <i32 1, i32 2>)
+}
diff --git a/tests/input/float.ll b/tests/input/float.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/float.ll
@@ -0,0 +1,21 @@
+define double @foo(double %a, double %b)  {
+entry:
+  %0 = fmul double %a, %a
+  %1 = fmul double %a, 2.000000e+00
+  %2 = fmul double %1, %b
+  %3 = fadd double %0, %2
+  %4 = fmul double %b, %b
+  %5 = fadd double %4, %3
+  ret double %5
+}
+
+define double @bar(double %a) {
+entry:
+  %0 = alloca double
+  store double %a, double* %0
+  %1 = load double, double* %0
+  %2 = call double @foo(double %1, double 4.000000e+00)
+  %3 = call double @bar(double 3.133700e+04)
+  %4 = fadd double %2, %3
+  ret double %4
+}
diff --git a/tests/input/for.ll b/tests/input/for.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/for.ll
@@ -0,0 +1,45 @@
+; ModuleID = 'simple module'
+
+declare i32 @foo()
+
+define i32 @forloop() {
+entry:
+  %0 = alloca i32
+  store i32 0, i32* %0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %1 = load i32, i32* %0
+  br i1 true, label %for.loop, label %for.exit
+
+for.loop:                                         ; preds = %for.cond
+  %2 = load i32, i32* %0
+  %3 = alloca i32
+  store i32 0, i32* %3
+  br label %for.cond1
+
+for.inc:                                          ; preds = %for.exit1
+  %4 = add i32 1, %2
+  store i32 %4, i32* %0
+  br label %for.cond
+
+for.exit:                                         ; preds = %for.cond
+  ret i32 0
+
+for.cond1:                                        ; preds = %for.inc1, %for.loop
+  %5 = load i32, i32* %3
+  br i1 true, label %for.loop1, label %for.exit1
+
+for.loop1:                                        ; preds = %for.cond1
+  %6 = load i32, i32* %3
+  %7 = call i32 @foo()
+  br label %for.inc1
+
+for.inc1:                                         ; preds = %for.loop1
+  %8 = add i32 1, %6
+  store i32 %8, i32* %3
+  br label %for.cond1
+
+for.exit1:                                        ; preds = %for.cond1
+  br label %for.inc
+}
diff --git a/tests/input/full.ll b/tests/input/full.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/full.ll
@@ -0,0 +1,50 @@
+; ModuleID = 'simple module'
+
+@"%i" = global [3 x i8] c"%i\00"
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+  %0 = alloca i32
+  store i32 0, i32* %0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %1 = load i32, i32* %0
+  %2 = icmp ult i32 %1, 15
+  br i1 %2, label %for.loop, label %for.exit
+
+for.loop:                                         ; preds = %for.cond
+  %3 = load i32, i32* %0
+  %4 = alloca i32
+  store i32 0, i32* %4
+  br label %for.cond1
+
+for.inc:                                          ; preds = %for.exit1
+  %5 = add i32 1, %3
+  store i32 %5, i32* %0
+  br label %for.cond
+
+for.exit:                                         ; preds = %for.cond
+  ret i32 0
+
+for.cond1:                                        ; preds = %for.inc1, %for.loop
+  %6 = load i32, i32* %4
+  %7 = icmp ult i32 %6, 15
+  br i1 %7, label %for.loop1, label %for.exit1
+
+for.loop1:                                        ; preds = %for.cond1
+  %8 = load i32, i32* %4
+  %9 = add i32 %3, %8
+  %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"%i", i32 0, i32 0), i32 %9)
+  br label %for.inc1
+
+for.inc1:                                         ; preds = %for.loop1
+  %11 = add i32 1, %8
+  store i32 %11, i32* %4
+  br label %for.cond1
+
+for.exit1:                                        ; preds = %for.cond1
+  br label %for.inc
+}
diff --git a/tests/input/func.ll b/tests/input/func.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/func.ll
@@ -0,0 +1,166 @@
+$f70 = comdat any
+$com1 = comdat exactmatch
+
+; Plain function declaration.
+declare void @f1()
+
+; Metadata.
+declare !foo !{!"bar"} !baz !{!"qux"} void @f2()
+
+; External linkage.
+declare extern_weak void @f3()
+declare external void @f4()
+
+; Visibility.
+declare default void @f5()
+declare hidden void @f6()
+declare protected void @f7()
+
+; DLL storage class.
+declare dllimport void @f8()
+declare dllexport void @f9()
+
+; Calling conventions.
+declare amdgpu_cs void @f10()
+declare amdgpu_gs void @f11()
+declare amdgpu_kernel void @f12()
+declare amdgpu_ps void @f13()
+declare amdgpu_vs void @f14()
+declare anyregcc void @f15()
+declare arm_aapcs_vfpcc void @f16()
+declare arm_aapcscc void @f17()
+declare arm_apcscc void @f18()
+declare avr_intrcc void @f19()
+declare avr_signalcc void @f20()
+declare cc 0 void @f21()
+declare ccc void @f22()
+declare coldcc void @f23()
+declare cxx_fast_tlscc void @f24()
+declare fastcc void @f25()
+declare ghccc void @f26()
+declare hhvm_ccc void @f27()
+declare hhvmcc void @f28()
+declare intel_ocl_bicc void @f29()
+declare msp430_intrcc void @f30()
+declare preserve_allcc void @f31()
+declare preserve_mostcc void @f32()
+declare ptx_device void @f33()
+declare ptx_kernel void @f34()
+declare spir_func void @f35()
+declare spir_kernel void @f36()
+declare swiftcc void @f37()
+declare webkit_jscc void @f38()
+declare x86_64_sysvcc void @f39()
+declare win64cc void @f40()
+declare x86_fastcallcc void @f41()
+declare x86_intrcc void @f42()
+declare x86_regcallcc void @f43()
+declare x86_stdcallcc void @f44()
+declare x86_thiscallcc void @f45()
+declare x86_vectorcallcc void @f46()
+
+; Return parameter attributes.
+declare "foo" "bar"="baz" align 8 dereferenceable(11) dereferenceable_or_null(22) inreg noalias i32 @f47()
+declare nonnull i32 ()* @f48()
+declare signext i32 @f49()
+declare zeroext i32 @f50()
+
+; Parameters.
+declare void @f51()
+declare void @f52(i32)
+declare void @f53(i32 %x)
+declare void @f54(i32, i32)
+declare void @f55(i32, i32 %y)
+declare void @f56(i32 %x, i32)
+declare void @f57(i32 %x, i32 %y)
+
+; Variadic function.
+declare void @f58(...)
+declare void @f59(i32, ...)
+declare void @f60(i32 %x, ...)
+declare void @f61(i32, i32, ...)
+declare void @f62(i32, i32 %y, ...)
+declare void @f63(i32 %x, i32, ...)
+declare void @f64(i32 %x, i32 %y, ...)
+
+; Parameter attributes.
+declare void @f65(i32 "foo" "bar"="baz" align 8 byval dereferenceable(11) dereferenceable_or_null(22) inalloca inreg nest noalias nocapture nonnull readnone readonly returned signext sret swifterror swiftself writeonly zeroext %x)
+
+; Unnamed address.
+declare void @f66() local_unnamed_addr
+declare void @f67() unnamed_addr
+
+; Function attributes.
+declare void @f68() "foo" "bar"="baz" #0 #1 alignstack(8) allocsize(16) allocsize(32, 64) alwaysinline argmemonly 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
+
+; Section.
+declare void @f69() section "foo"
+
+; Comdat.
+declare void @f70() comdat
+declare void @f71() comdat($com1)
+
+; Align.
+declare void @f72() align 8
+
+; Garbage collection.
+declare void @f73() gc "foo"
+
+; Function prefix data.
+declare void @f74() prefix i32 42
+
+; Function prologue data.
+declare void @f75() prologue i32 42
+
+; Function personality data.
+declare void @f76() personality i32 42
+
+; Full function declaration.
+declare !foo !{!"bar"} !baz !{!"qux"} external default dllimport ccc "foo" "bar"="baz" align 8 dereferenceable(11) dereferenceable_or_null(22) inreg noalias i32 @f77(i32 %x, i32 "foo" "bar"="baz" align 8 byval dereferenceable(11) dereferenceable_or_null(22) inalloca inreg nest noalias nocapture nonnull readnone readonly returned signext sret swifterror swiftself writeonly zeroext %y, ...) unnamed_addr "foo" "bar"="baz" #0 #1 alignstack(8) allocsize(16) allocsize(32, 64) alwaysinline argmemonly 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 section "foo" comdat($com1) align 8 gc "foo" prefix i32 42 prologue i32 42 personality i32 42
+
+; Plain function definition.
+define void @f78() {
+	ret void
+}
+
+; Linkage.
+define available_externally void @f80() {
+	ret void
+}
+
+define internal void @f82() {
+	ret void
+}
+
+define linkonce void @f83() {
+	ret void
+}
+
+define linkonce_odr void @f84() {
+	ret void
+}
+
+define private void @f85() {
+	ret void
+}
+
+define weak void @f86() {
+	ret void
+}
+
+define weak_odr void @f87() {
+	ret void
+}
+
+; Metadata.
+define void @f88() !foo !{!"bar"} !baz !{!"qux"} {
+	ret void
+}
+
+; Full function definition.
+define available_externally default dllimport ccc "foo" "bar"="baz" align 8 dereferenceable(11) dereferenceable_or_null(22) inreg noalias i32 @f89(i32 %x, i32 "foo" "bar"="baz" align 8 byval dereferenceable(11) dereferenceable_or_null(22) inalloca inreg nest noalias nocapture nonnull readnone readonly returned signext sret swifterror swiftself writeonly zeroext %y, ...) unnamed_addr "foo" "bar"="baz" #0 #1 alignstack(8) allocsize(16) allocsize(32, 64) alwaysinline argmemonly 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 section "foo" comdat($com1) align 8 gc "foo" prefix i32 42 prologue i32 42 personality i32 42 !foo !{!"bar"} !baz !{!"qux"} {
+	ret i32 42
+}
+
+attributes #0 = { "foo" }
+attributes #1 = { "foo" "bar"="baz" #0 alignstack=8 allocsize(16) allocsize(16, 32) 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 }
diff --git a/tests/input/getelementptr.ll b/tests/input/getelementptr.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/getelementptr.ll
@@ -0,0 +1,13 @@
+define i32 @main() {
+; <label>:0
+	%1 = alloca [4 x i32]
+	%2 = getelementptr [4 x i32], [4 x i32]* %1, i64 0, i64 0
+	store i32 0, i32* %2
+	%3 = getelementptr [4 x i32], [4 x i32]* %1, i64 0, i64 1
+	store i32 1, i32* %3
+	%4 = getelementptr [4 x i32], [4 x i32]* %1, i64 0, i64 2
+	store i32 2, i32* %4
+	%5 = getelementptr [4 x i32], [4 x i32]* %1, i64 0, i64 3
+	store i32 3, i32* %5
+	ret i32 0
+}
diff --git a/tests/input/global.ll b/tests/input/global.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/global.ll
@@ -0,0 +1,77 @@
+$g29 = comdat any
+$com1 = comdat exactmatch
+
+; Mutable.
+@g1 = global i32 0
+
+; Immutable.
+@g2 = constant i32 0
+
+; External linkage.
+@g3 = external global i32
+@g4 = extern_weak global i32
+
+; Linkage.
+@g5 = appending global i32 0
+@g6 = available_externally global i32 0
+@g7 = common global i32 0
+@g8 = internal global i32 0
+@g9 = linkonce global i32 0
+@g10 = linkonce_odr global i32 0
+@g11 = private global i32 0
+@g12 = weak global i32 0
+@g13 = weak_odr global i32 0
+
+; Visibility.
+@g14 = default global i32 0
+@g15 = hidden global i32 0
+@g16 = protected global i32 0
+
+; DLL storage class.
+@g17 = dllimport global i32 0
+@g18 = dllexport global i32 0
+
+; Thread local storage.
+@g19 = thread_local global i32 0
+@g20 = thread_local(localdynamic) global i32 0
+@g21 = thread_local(initialexec) global i32 0
+@g22 = thread_local(localexec) global i32 0
+
+; Unnamed address.
+@g23 = local_unnamed_addr global i32 0
+@g24 = unnamed_addr global i32 0
+
+; Address space.
+@g25 = addrspace(1) global i32 0
+@g26 = external addrspace(1) global i32
+
+; Externally initialized.
+@g27 = externally_initialized global i32 0
+
+; Section.
+@g28 = global i32 0, section "foo"
+
+; Comdat.
+@g29 = global i32 0, comdat
+@g30 = global i32 0, comdat($com1)
+
+; Align.
+@g31 = global i32 0, align 8
+
+; Metadata.
+@g32 = global i32 0, !foo !{!"bar"}, !baz !{!"qux"}
+
+; Full global definition.
+@g33 = common default dllexport thread_local(localdynamic) unnamed_addr addrspace(1) externally_initialized global i32 0, section "foo", comdat($com1), align 8, !foo !{!"bar"}, !baz !{!"qux"}
+
+; Permutations of global declarations and definitions.
+@g34 = external global i32, align 8
+@g35 = external global i32, comdat($com1), align 8
+@g36 = external global i32, comdat($com1)
+@g37 = external global i32, section "foo", align 8
+@g38 = external global i32, section "foo", comdat($com1), align 8
+@g39 = external global i32, section "foo", comdat($com1)
+@g40 = external global i32, section "foo"
+@g41 = global i32 42 ,comdat($com1), align 8
+@g42 = global i32 42 ,section "foo", align 8
+@g43 = global i32 42 ,section "foo", comdat($com1)
diff --git a/tests/input/hello.ll b/tests/input/hello.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/hello.ll
@@ -0,0 +1,16 @@
+; ModuleID = 'hello.c'
+@.str = private unnamed_addr constant [12 x i8] c"Hello World\00", align 1
+
+; Function Attrs: noinline nounwind uwtable
+define i32 @main(i32, i8**) #0 {
+  %3 = alloca i32, align 4
+  %4 = alloca i32, align 4
+  %5 = alloca i8**, align 8
+  store i32 0, i32* %3, align 4
+  store i32 %0, i32* %4, align 4
+  store i8** %1, i8*** %5, align 8
+  %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0))
+  ret i32 0
+}
+
+declare i32 @printf(i8*, ...) #1
diff --git a/tests/input/if.ll b/tests/input/if.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/if.ll
@@ -0,0 +1,19 @@
+; ModuleID = 'simple module'
+
+define i32 @foo(i1 %x) {
+entry:
+  %x.addr = alloca i1
+  store i1 %x, i1* %x.addr
+  %0 = load i1, i1* %x.addr
+  br i1 %0, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  br label %if.exit
+
+if.else:                                          ; preds = %entry
+  br label %if.exit
+
+if.exit:                                          ; preds = %if.else, %if.then
+  %1 = phi i32 [ 1, %if.then ], [ 2, %if.else ]
+  ret i32 %1
+}
diff --git a/tests/input/inst_aggregate.ll b/tests/input/inst_aggregate.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_aggregate.ll
@@ -0,0 +1,41 @@
+; --- [ Aggregate instructions ] -----------------------------------------------
+
+; ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @extractvalue_1() {
+	; Plain instruction.
+	%result = extractvalue { i8, i32 } { i8 21, i32 42 }, 1
+	ret i32 %result
+}
+
+define i32 @extractvalue_2() {
+	; Nested struct and array operand.
+	%result = extractvalue { i32, { [2 x i32], i8 } } { i32 0, { [2 x i32], i8 } { [2 x i32] [i32 100, i32 42], i8 11 } }, 1, 0, 1
+	ret i32 %result
+}
+
+define i32 @extractvalue_3() {
+	; Metadata.
+	%result = extractvalue { i8, i32 } { i8 21, i32 42 }, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define { i32, i32 } @insertvalue_1() {
+	; Plain instruction.
+	%result = insertvalue { i32, i32 } { i32 21, i32 42 }, i32 42, 0
+	ret { i32, i32 } %result
+}
+
+define { i32, { [2 x i32], i32 } } @insertvalue_2() {
+	; Nested struct and array operand.
+	%result = insertvalue { i32, { [2 x i32], i32 } } { i32 42, { [2 x i32], i32 } { [2 x i32] [i32 100, i32 42], i32 42 } }, i32 42, 1, 0, 0
+	ret { i32, { [2 x i32], i32 } } %result
+}
+
+define { i32, i32 } @insertvalue_3() {
+	; Metadata.
+	%result = insertvalue { i32, i32 } { i32 21, i32 42 }, i32 42, 0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret { i32, i32 } %result
+}
diff --git a/tests/input/inst_binary.ll b/tests/input/inst_binary.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_binary.ll
@@ -0,0 +1,361 @@
+; --- [ Binary instructions ] --------------------------------------------------
+
+; ~~~ [ add ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @add_1() {
+	; Plain instruction.
+	%result = add i32 30, 12
+	ret i32 %result
+}
+
+define <2 x i32> @add_2() {
+	; Vector operands.
+	%result = add <2 x i32> <i32 30, i32 12>, <i32 12, i32 30>
+	ret <2 x i32> %result
+}
+
+define i32 @add_3() {
+	; Overflow flags.
+	%result = add nsw nuw i32 30, 12
+	ret i32 %result
+}
+
+define i32 @add_4() {
+	; Metadata.
+	%result = add i32 30, 12, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @add_5() {
+	; Full instruction.
+	%result = add nsw nuw i32 30, 12, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fadd ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fadd_1() {
+	; Plain instruction.
+	%result = fadd double 30.0, 12.0
+	ret double %result
+}
+
+define <2 x double> @fadd_2() {
+	; Vector operands.
+	%result = fadd <2 x double> <double 30.0, double 12.0>, <double 12.0, double 30.0>
+	ret <2 x double> %result
+}
+
+define double @fadd_3() {
+	; Fast-math flags.
+	%result = fadd arcp fast ninf nnan nsz double 30.0, 12.0
+	ret double %result
+}
+
+define double @fadd_4() {
+	; Metadata.
+	%result = fadd double 30.0, 12.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+define double @fadd_5() {
+	; Full instruction.
+	%result = fadd arcp fast ninf nnan nsz double 30.0, 12.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ sub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sub_1() {
+	; Plain instruction.
+	%result = sub i32 50, 8
+	ret i32 %result
+}
+
+define <2 x i32> @sub_2() {
+	; Vector operands.
+	%result = sub <2 x i32> <i32 50, i32 -8>, <i32 8, i32 -50>
+	ret <2 x i32> %result
+}
+
+define i32 @sub_3() {
+	; Overflow flags.
+	%result = sub nsw nuw i32 50, 8
+	ret i32 %result
+}
+
+define i32 @sub_4() {
+	; Metadata.
+	%result = sub i32 50, 8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @sub_5() {
+	; Full instruction.
+	%result = sub nsw nuw i32 50, 8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fsub ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fsub_1() {
+	; Plain instruction.
+	%result = fsub double 50.0, 8.0
+	ret double %result
+}
+
+define <2 x double> @fsub_2() {
+	; Vector operands.
+	%result = fsub <2 x double> <double 50.0, double -8.0>, <double 8.0, double -50.0>
+	ret <2 x double> %result
+}
+
+define double @fsub_3() {
+	; Fast-math flags.
+	%result = fsub arcp fast ninf nnan nsz double 50.0, 8.0
+	ret double %result
+}
+
+define double @fsub_4() {
+	; Metadata.
+	%result = fsub double 50.0, 8.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+define double @fsub_5() {
+	; Full instruction.
+	%result = fsub arcp fast ninf nnan nsz double 50.0, 8.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ mul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @mul_1() {
+	; Plain instruction.
+	%result = mul i32 21, 2
+	ret i32 %result
+}
+
+define <2 x i32> @mul_2() {
+	; Vector operands.
+	%result = mul <2 x i32> <i32 21, i32 2>, <i32 2, i32 21>
+	ret <2 x i32> %result
+}
+
+define i32 @mul_3() {
+	; Overflow flags.
+	%result = mul nsw nuw i32 21, 2
+	ret i32 %result
+}
+
+define i32 @mul_4() {
+	; Metadata.
+	%result = mul i32 21, 2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @mul_5() {
+	; Full instruction.
+	%result = mul nsw nuw i32 21, 2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fmul ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fmul_1() {
+	; Plain instruction.
+	%result = fmul double 21.0, 2.0
+	ret double %result
+}
+
+define <2 x double> @fmul_2() {
+	; Vector operands.
+	%result = fmul <2 x double> <double 21.0, double 2.0>, <double 2.0, double 21.0>
+	ret <2 x double> %result
+}
+
+define double @fmul_3() {
+	; Fast-math flags.
+	%result = fmul arcp fast ninf nnan nsz double 21.0, 2.0
+	ret double %result
+}
+
+define double @fmul_4() {
+	; Metadata.
+	%result = fmul double 21.0, 2.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+define double @fmul_5() {
+	; Full instruction.
+	%result = fmul arcp fast ninf nnan nsz double 21.0, 2.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ udiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @udiv_1() {
+	; Plain instruction.
+	%result = udiv i32 84, 2
+	ret i32 %result
+}
+
+define <2 x i32> @udiv_2() {
+	; Vector operands.
+	%result = udiv <2 x i32> <i32 84, i32 42>, <i32 2, i32 1>
+	ret <2 x i32> %result
+}
+
+define i32 @udiv_3() {
+	; Exact.
+	%result = udiv exact i32 84, 2
+	ret i32 %result
+}
+
+define i32 @udiv_4() {
+	; Metadata.
+	%result = udiv i32 84, 2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @udiv_5() {
+	; Full instruction.
+	%result = udiv exact i32 84, 2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ sdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sdiv_1() {
+	; Plain instruction.
+	%result = sdiv i32 -84, -2
+	ret i32 %result
+}
+
+define <2 x i32> @sdiv_2() {
+	; Vector operands.
+	%result = sdiv <2 x i32> <i32 -84, i32 42>, <i32 -2, i32 1>
+	ret <2 x i32> %result
+}
+
+define i32 @sdiv_3() {
+	; Exact.
+	%result = sdiv exact i32 -84, -2
+	ret i32 %result
+}
+
+define i32 @sdiv_4() {
+	; Metadata.
+	%result = sdiv i32 -84, -2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @sdiv_5() {
+	; Full instruction.
+	%result = sdiv exact i32 -84, -2, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fdiv ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fdiv_1() {
+	; Plain instruction.
+	%result = fdiv double 84.0, 2.0
+	ret double %result
+}
+
+define <2 x double> @fdiv_2() {
+	; Vector operands.
+	%result = fdiv <2 x double> <double 84.0, double 42.0>, <double 2.0, double 1.0>
+	ret <2 x double> %result
+}
+
+define double @fdiv_3() {
+	; Fast-math flags.
+	%result = fdiv arcp fast ninf nnan nsz double 84.0, 2.0
+	ret double %result
+}
+
+define double @fdiv_4() {
+	; Metadata.
+	%result = fdiv double 84.0, 2.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+define double @fdiv_5() {
+	; Full instruction.
+	%result = fdiv arcp fast ninf nnan nsz double 84.0, 2.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ urem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @urem_1() {
+	; Plain instruction.
+	%result = urem i32 85, 43
+	ret i32 %result
+}
+
+define <2 x i32> @urem_2() {
+	; Vector operands.
+	%result = urem <2 x i32> <i32 85, i32 162>, <i32 43, i32 60>
+	ret <2 x i32> %result
+}
+
+define i32 @urem_3() {
+	; Metadata.
+	%result = urem i32 85, 43, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ srem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @srem_1() {
+	; Plain instruction.
+	%result = srem i32 85, -43
+	ret i32 %result
+}
+
+define <2 x i32> @srem_2() {
+	; Vector operands.
+	%result = srem <2 x i32> <i32 85, i32 162>, <i32 -43, i32 -60>
+	ret <2 x i32> %result
+}
+
+define i32 @srem_3() {
+	; Metadata.
+	%result = srem i32 85, -43, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ frem ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @frem_1() {
+	; Plain instruction.
+	%result = frem double 85.0, 43.0
+	ret double %result
+}
+
+define <2 x double> @frem_2() {
+	; Vector operands.
+	%result = frem <2 x double> <double 85.0, double 162.0>, <double 43.0, double 60.0>
+	ret <2 x double> %result
+}
+
+define double @frem_3() {
+	; Fast-math flags.
+	%result = frem arcp fast ninf nnan nsz double 85.0, 43.0
+	ret double %result
+}
+
+define double @frem_4() {
+	; Metadata.
+	%result = frem double 85.0, 43.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+define double @frem_5() {
+	; Full instruction.
+	%result = frem arcp fast ninf nnan nsz double 85.0, 43.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
diff --git a/tests/input/inst_bitwise.ll b/tests/input/inst_bitwise.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_bitwise.ll
@@ -0,0 +1,163 @@
+; --- [ Bitwise instructions ] -------------------------------------------------
+
+; ~~~ [ shl ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @shl_1() {
+	; Plain instruction.
+	%result = shl i32 21, 1
+	ret i32 %result
+}
+
+define <2 x i32> @shl_2() {
+	; Vector operands.
+	%result = shl <2 x i32> <i32 21, i32 42>, <i32 1, i32 0>
+	ret <2 x i32> %result
+}
+
+define i32 @shl_3() {
+	; Overflow flags.
+	%result = shl nsw nuw i32 21, 1
+	ret i32 %result
+}
+
+define i32 @shl_4() {
+	; Metadata.
+	%result = shl i32 21, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @shl_5() {
+	; Full instruction.
+	%result = shl nsw nuw i32 21, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ lshr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @lshr_1() {
+	; Plain instruction.
+	%result = lshr i32 84, 1
+	ret i32 %result
+}
+
+define <2 x i32> @lshr_2() {
+	; Vector operands.
+	%result = lshr <2 x i32> <i32 84, i32 42>, <i32 1, i32 0>
+	ret <2 x i32> %result
+}
+
+define i32 @lshr_3() {
+	; Exact.
+	%result = lshr exact i32 84, 1
+	ret i32 %result
+}
+
+define i32 @lshr_4() {
+	; Metadata.
+	%result = lshr i32 84, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @lshr_5() {
+	; Full instruction.
+	%result = lshr exact i32 84, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ ashr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @ashr_1() {
+	; Plain instruction.
+	%result = ashr i32 84, 1
+	ret i32 %result
+}
+
+define <2 x i32> @ashr_2() {
+	; Vector operands.
+	%result = ashr <2 x i32> <i32 84, i32 42>, <i32 1, i32 0>
+	ret <2 x i32> %result
+}
+
+define i32 @ashr_3() {
+	; Exact.
+	%result = ashr exact i32 84, 1
+	ret i32 %result
+}
+
+define i32 @ashr_4() {
+	; Metadata.
+	%result = ashr i32 84, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @ashr_5() {
+	; Negative operand.
+	%result = ashr i32 -84, 1
+	ret i32 %result
+}
+
+define i32 @ashr_6() {
+	; Full instruction.
+	%result = ashr exact i32 84, 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ and ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @and_1() {
+	; Plain instruction.
+	%result = and i32 58, 239 ; 0b00111010 & 0b11101111
+	ret i32 %result
+}
+
+define <2 x i32> @and_2() {
+	; Vector operands.
+	%result = and <2 x i32> <i32 58, i32 170>, <i32 239, i32 127> ; 0b00111010 & 0b11101111, 0b10101010 & 0b01111111
+	ret <2 x i32> %result
+}
+
+define i32 @and_3() {
+	; Metadata.
+	%result = and i32 58, 239, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ or ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @or_1() {
+	; Plain instruction.
+	%result = or i32 10, 32 ; 0b00001010 | 0b0100000
+	ret i32 %result
+}
+
+define <2 x i32> @or_2() {
+	; Vector operands.
+	%result = or <2 x i32> <i32 10, i32 40>, <i32 32, i32 2> ; 0b00001010 | 0b0100000, 0b00101000 & 0b00000010
+	ret <2 x i32> %result
+}
+
+define i32 @or_3() {
+	; Metadata.
+	%result = or i32 10, 32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ xor ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @xor_1() {
+	; Plain instruction.
+	%result = xor i32 255, 213 ; 0b11111111 ^ 0b11010101
+	ret i32 %result
+}
+
+define <2 x i32> @xor_2() {
+	; Vector operands.
+	%result = xor <2 x i32> <i32 255, i32 123>, <i32 213, i32 81> ; 0b11111111 ^ 0b11010101, 0b01111011 ^ 0b01010001
+	ret <2 x i32> %result
+}
+
+define i32 @xor_3() {
+	; Metadata.
+	%result = xor i32 255, 213, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
diff --git a/tests/input/inst_conversion.ll b/tests/input/inst_conversion.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_conversion.ll
@@ -0,0 +1,199 @@
+; --- [ Conversion instructions ] ----------------------------------------------
+
+; ~~~ [ trunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8 @trunc_1() {
+	; Plain instruction.
+	%result = trunc i32 298 to i8
+	ret i8 %result
+}
+
+define i8 @trunc_2() {
+	; Metadata.
+	%result = trunc i32 298 to i8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i8 %result
+}
+
+; ~~~ [ zext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @zext_1() {
+	; Plain instruction.
+	%result = zext i8 42 to i32
+	ret i32 %result
+}
+
+define i32 @zext_2() {
+	; Metadata.
+	%result = zext i8 42 to i32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ sext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @sext_1() {
+	; Plain instruction.
+	%result = sext i8 -42 to i32
+	ret i32 %result
+}
+
+define i32 @sext_2() {
+	; Metadata.
+	%result = sext i8 -42 to i32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fptrunc ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define float @fptrunc_1() {
+	; Plain instruction.
+	%result = fptrunc double 42.0 to float
+	ret float %result
+}
+
+define float @fptrunc_2() {
+	; Metadata.
+	%result = fptrunc double 42.0 to float, !foo !{!"bar"}, !baz !{!"qux"}
+	ret float %result
+}
+
+; ~~~ [ fpext ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @fpext_1() {
+	; Plain instruction.
+	%result = fpext float 42.0 to double
+	ret double %result
+}
+
+define double @fpext_2() {
+	; Metadata.
+	%result = fpext float 42.0 to double, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ fptoui ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @fptoui_1() {
+	; Plain instruction.
+	%result = fptoui double 42.0 to i32
+	ret i32 %result
+}
+
+define i32 @fptoui_2() {
+	; Metadata.
+	%result = fptoui double 42.0 to i32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ fptosi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @fptosi_1() {
+	; Plain instruction.
+	%result = fptosi double -42.0 to i32
+	ret i32 %result
+}
+
+define i32 @fptosi_2() {
+	; Metadata.
+	%result = fptosi double -42.0 to i32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ uitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @uitofp_1() {
+	; Plain instruction.
+	%result = uitofp i32 42 to double
+	ret double %result
+}
+
+define double @uitofp_2() {
+	; Metadata.
+	%result = uitofp i32 42 to double, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ sitofp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define double @sitofp_1() {
+	; Plain instruction.
+	%result = sitofp i32 -42 to double
+	ret double %result
+}
+
+define double @sitofp_2() {
+	; Metadata.
+	%result = sitofp i32 -42 to double, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ ptrtoint ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i64 @ptrtoint_1() {
+	; Plain instruction.
+	%result = ptrtoint i8* null to i64
+	ret i64 %result
+}
+
+define i64 @ptrtoint_2(i8* %x) {
+	; Local operand.
+	%result = ptrtoint i8* %x to i64
+	ret i64 %result
+}
+
+define void @f() {
+	ret void
+}
+
+define i64 @ptrtoint_3() {
+	; Global operand.
+	%result = ptrtoint void ()* @f to i64
+	ret i64 %result
+}
+
+define i64 @ptrtoint_4() {
+	; Metadata.
+	%result = ptrtoint i8* null to i64, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i64 %result
+}
+
+; ~~~ [ inttoptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8* @inttoptr_1() {
+	; Plain instruction.
+	%result = inttoptr i32 0 to i8*
+	ret i8* %result
+}
+
+define i8* @inttoptr_2() {
+	; Metadata.
+	%result = inttoptr i32 0 to i8*, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i8* %result
+}
+
+; ~~~ [ bitcast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <4 x i8> @bitcast_1() {
+	; Plain instruction.
+	%result = bitcast i32 707406378 to <4 x i8>
+	ret <4 x i8> %result
+}
+
+define <4 x i8> @bitcast_2() {
+	; Metadata.
+	%result = bitcast i32 707406378 to <4 x i8>, !foo !{!"bar"}, !baz !{!"qux"}
+	ret <4 x i8> %result
+}
+
+; ~~~ [ addrspacecast ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i8 addrspace(2)* @addrspacecast_1() {
+	; Plain instruction.
+	%result = addrspacecast i8 addrspace(1)* null to i8 addrspace(2)*
+	ret i8 addrspace(2)* %result
+}
+
+define i8 addrspace(2)* @addrspacecast_2() {
+	; Metadata.
+	%result = addrspacecast i8 addrspace(1)* null to i8 addrspace(2)*, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i8 addrspace(2)* %result
+}
diff --git a/tests/input/inst_memory.ll b/tests/input/inst_memory.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_memory.ll
@@ -0,0 +1,188 @@
+; --- [ Memory instructions ] --------------------------------------------------
+
+@x = global i32 42
+
+; ~~~ [ alloca ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32* @alloca_1() {
+	; Plain instruction.
+	%result = alloca i32
+	ret i32* %result
+}
+
+define i32* @alloca_2() {
+	; Number of elements operand.
+	%result = alloca i32, i32 10
+	ret i32* %result
+}
+
+define i32* @alloca_3() {
+	; Alignment operand.
+	%result = alloca i32, align 8
+	ret i32* %result
+}
+
+define i32* @alloca_4() {
+	; Metadata.
+	%result = alloca i32, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32* %result
+}
+
+define i32* @alloca_5() {
+	; Full instruction.
+	%result = alloca i32, i32 10, align 8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32* %result
+}
+
+; ~~~ [ load ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @load_1(i32* %x) {
+	; Plain instruction.
+	%result = load i32, i32* %x
+	ret i32 %result
+}
+
+define i32 @load_2() {
+	; Global operand.
+	%result = load i32, i32* @x
+	ret i32 %result
+}
+
+define i32 @load_3(i32* %x) {
+	; Volatile.
+	%result = load volatile i32, i32* %x
+	ret i32 %result
+}
+
+define i32 @load_4(i32* %x) {
+	; Alignment operand.
+	%result = load i32, i32* %x, align 8
+	ret i32 %result
+}
+
+define i32 @load_5(i32* %x) {
+	; Metadata.
+	%result = load i32, i32* %x, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define i32 @load_6(i32* %x) {
+	; Full instruction.
+	%result = load volatile i32, i32* %x, align 8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ store ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @store_1(i32* %x) {
+	; Plain instruction.
+	store i32 42, i32* %x
+	ret void
+}
+
+define void @store_2() {
+	; Global operand.
+	store i32 42, i32* @x
+	ret void
+}
+
+define void @store_3(i32* %x) {
+	; Volatile.
+	store volatile i32 42, i32* %x
+	ret void
+}
+
+define void @store_4(i32* %x) {
+	; Alignment operand.
+	store i32 42, i32* %x, align 8
+	ret void
+}
+
+define void @store_5(i32* %x) {
+	; Metadata.
+	store i32 42, i32* %x, !foo !{!"bar"}, !baz !{!"qux"}
+	ret void
+}
+
+define void @store_6(i32* %x) {
+	; Full instruction.
+	store volatile i32 42, i32* %x, align 8, !foo !{!"bar"}, !baz !{!"qux"}
+	ret void
+}
+
+; ~~~ [ fence ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @fence() {
+    fence syncscope("singlethread") seq_cst
+    fence acquire
+    fence release
+    fence acq_rel
+    ret void
+}
+
+; ~~~ [ cmpxchg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @cmpxchg_1(i32* %ptr) {
+  entry:
+    %orig = load atomic i32, i32* %ptr unordered, align 4
+    br label %loop
+
+  loop:
+    %cmp = phi i32 [ %orig, %entry ], [%value_loaded, %loop]
+    %squared = mul i32 %cmp, %cmp
+    %val_success = cmpxchg i32* %ptr, i32 %cmp, i32 %squared acq_rel monotonic
+    %value_loaded = extractvalue { i32, i1 } %val_success, 0
+    %success = extractvalue { i32, i1 } %val_success, 1
+    br i1 %success, label %done, label %loop
+  done:
+    ret void
+}
+
+; ~~~ [ atomicrmw ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @atomicrmw(i8* %Q, i32* %word, i32* %x) {
+    atomicrmw add i8* %Q, i8 1 monotonic
+    atomicrmw add i32* %x, i32 10 seq_cst
+    atomicrmw volatile umin i32* %word, i32 22 syncscope("singlethread") monotonic
+    ret void
+}
+
+; ~~~ [ resume ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+declare i32 @__gxx_personality_v0(...)
+
+define void @resume() personality i32 (...)* @__gxx_personality_v0 {
+ resume { i8*, i32 } { i8* bitcast (void ()* @resume to i8*), i32 42 }
+}
+
+; ~~~ [ getelementptr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32* @getelementptr_1(i32* %x) {
+	; Plain instruction.
+	%result = getelementptr i32, i32* %x
+	ret i32* %result
+}
+
+define i32* @getelementptr_2({ i32, { [2 x i32], i8 } }* %x) {
+	; Indices.
+	%result = getelementptr { i32, { [2 x i32], i8 } }, { i32, { [2 x i32], i8 } }* %x, i32 0, i32 1, i32 0, i32 1
+	ret i32* %result
+}
+
+define i32* @getelementptr_3(i32* %x) {
+	; Inbounds.
+	%result = getelementptr inbounds i32, i32* %x
+	ret i32* %result
+}
+
+define i32* @getelementptr_4(i32* %x) {
+	; Metadata.
+	%result = getelementptr i32, i32* %x, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32* %result
+}
+
+define i32* @getelementptr_5({ i32, { [2 x i32], i8 } }* %x) {
+	; Full instruction.
+	%result = getelementptr inbounds { i32, { [2 x i32], i8 } }, { i32, { [2 x i32], i8 } }* %x, i32 0, i32 1, i32 0, i32 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32* %result
+}
diff --git a/tests/input/inst_other.ll b/tests/input/inst_other.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_other.ll
@@ -0,0 +1,439 @@
+; --- [ Other instructions ] ---------------------------------------------------
+
+@g1 = global i32 42
+
+; ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i1 @icmp_1() {
+	; Plain instruction.
+	%result = icmp ne i32 42, 5
+	ret i1 %result
+}
+
+define <2 x i1> @icmp_2() {
+	; Vector operands.
+	%result = icmp eq <2 x i32> <i32 42, i32 11>, <i32 42, i32 22>
+	ret <2 x i1> %result
+}
+
+define void @icmp_3() {
+	; Predicates.
+	%1 = icmp eq i32 10, 15
+	%2 = icmp ne i32 10, 15
+	%3 = icmp ugt i32 10, 15
+	%4 = icmp uge i32 10, 15
+	%5 = icmp ult i32 10, 15
+	%6 = icmp ule i32 10, 15
+	%7 = icmp sgt i32 10, 15
+	%8 = icmp sge i32 10, 15
+	%9 = icmp slt i32 10, 15
+	%10 = icmp sle i32 10, 15
+	ret void
+}
+
+define i1 @icmp_4() {
+	; Metadata.
+	%result = icmp ne i32 42, 5, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i1 %result
+}
+
+; ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i1 @fcmp_1() {
+	; Plain instruction.
+	%result = fcmp one double 42.0, 5.0
+	ret i1 %result
+}
+
+define <2 x i1> @fcmp_2() {
+	; Vector operands.
+	%result = fcmp oeq <2 x double> <double 42.0, double 11.0>, <double 42.0, double 22.0>
+	ret <2 x i1> %result
+}
+
+define void @fcmp_3() {
+	; Predicates.
+	%1 = fcmp false double 10.0, 15.0
+	%2 = fcmp oeq double 10.0, 15.0
+	%3 = fcmp ogt double 10.0, 15.0
+	%4 = fcmp oge double 10.0, 15.0
+	%5 = fcmp olt double 10.0, 15.0
+	%6 = fcmp ole double 10.0, 15.0
+	%7 = fcmp one double 10.0, 15.0
+	%8 = fcmp ord double 10.0, 15.0
+	%9 = fcmp ueq double 10.0, 15.0
+	%10 = fcmp ugt double 10.0, 15.0
+	%11 = fcmp uge double 10.0, 15.0
+	%12 = fcmp ult double 10.0, 15.0
+	%13 = fcmp ule double 10.0, 15.0
+	%14 = fcmp une double 10.0, 15.0
+	%15 = fcmp uno double 10.0, 15.0
+	%16 = fcmp true double 10.0, 15.0
+	ret void
+}
+
+define i1 @fcmp_4() {
+	; Fast-math flags.
+	%result = fcmp arcp fast ninf nnan nsz one double 42.0, 5.0
+	ret i1 %result
+}
+
+define i1 @fcmp_5() {
+	; Metadata.
+	%result = fcmp one double 42.0, 5.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i1 %result
+}
+
+define i1 @fcmp_6() {
+	; Full instruction.
+	%result = fcmp arcp fast ninf nnan nsz one double 42.0, 5.0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i1 %result
+}
+
+; ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @phi_1(i1 %cond) {
+entry:
+	; Plain instruction.
+	%result = phi i32 [ 42, %entry ]
+	ret i32 %result
+}
+
+define i32 @phi_2(i1 %cond) {
+	br i1 %cond, label %foo, label %bar
+foo:
+	br label %baz
+bar:
+	br label %baz
+baz:
+	; Multiple incoming branches.
+	%result = phi i32 [ 42, %foo ], [ 37, %bar ]
+	ret i32 %result
+}
+
+define void @phi_3(i1 %cond) {
+	br i1 %cond, label %foo, label %bar
+foo:
+	%x = fadd double 32.0, 10.0
+	br label %baz
+bar:
+	br label %baz
+baz:
+	; Incoming values of various types.
+	%1 = phi i32 [ 42, %foo ], [ 37, %bar ]
+	%2 = phi i32* [ null, %foo ], [ @g1, %bar ]
+	%3 = phi double [ %x, %foo ], [ 11.0, %bar ]
+	%4 = phi { i32 } [ { i32 42 }, %foo ], [ zeroinitializer, %bar ]
+	%5 = phi void ()* [ undef, %foo ], [ @j, %bar ]
+	ret void
+}
+
+define i32 @phi_4(i1 %cond) {
+	br i1 %cond, label %foo, label %bar
+foo:
+	br label %baz
+bar:
+	br label %baz
+baz:
+	; Metadata.
+	%result = phi i32 [ 42, %foo ], [ 37, %bar ], !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @select_1(i1 %cond) {
+	; Plain instruction.
+	%result = select i1 %cond, i32 42, i32 37
+	ret i32 %result
+}
+
+define <2 x i32> @select_2(i1 %cond) {
+	; Vector operands.
+	%result = select i1 %cond, <2 x i32> <i32 42, i32 37>, <2 x i32> <i32 11, i32 22>
+	ret <2 x i32> %result
+}
+
+define i32 @select_3(i1 %cond) {
+	; Metadata.
+	%result = select i1 %cond, i32 42, i32 37, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @f() {
+	ret i32 42
+}
+
+define i32 @call_1() {
+	; Plain instruction.
+	%result = call i32 @f()
+	ret i32 %result
+}
+
+define i32 @call_2() {
+	; Tail.
+	%result = tail call i32 @f()
+	ret i32 %result
+}
+
+define i32 @call_3() {
+	; Tail.
+	%result = musttail call i32 @f()
+	ret i32 %result
+}
+
+define i32 @call_4() {
+	; Tail.
+	%result = notail call i32 @f()
+	ret i32 %result
+}
+
+define double @g() {
+	ret double 42.0
+}
+
+define double @call_5() {
+	; Fast-math flags.
+	%result = call arcp fast ninf nnan nsz double @g()
+	ret double %result
+}
+
+define void @call_6() {
+	; Calling convention.
+	%1 = call amdgpu_cs i32 @f()
+	%2 = call amdgpu_gs i32 @f()
+	%3 = call amdgpu_kernel i32 @f()
+	%4 = call amdgpu_ps i32 @f()
+	%5 = call amdgpu_vs i32 @f()
+	%6 = call anyregcc i32 @f()
+	%7 = call arm_aapcs_vfpcc i32 @f()
+	%8 = call arm_aapcscc i32 @f()
+	%9 = call arm_apcscc i32 @f()
+	%10 = call avr_intrcc i32 @f()
+	%11 = call avr_signalcc i32 @f()
+	%12 = call cc 0 i32 @f()
+	%13 = call cc 8 i32 @f()
+	%14 = call cc 9 i32 @f()
+	%15 = call cc 10 i32 @f()
+	%16 = call cc 11 i32 @f()
+	%17 = call cc 12 i32 @f()
+	%18 = call cc 13 i32 @f()
+	%19 = call cc 14 i32 @f()
+	%20 = call cc 15 i32 @f()
+	%21 = call cc 16 i32 @f()
+	%22 = call cc 17 i32 @f()
+	%23 = call cc 64 i32 @f()
+	%24 = call cc 65 i32 @f()
+	%25 = call cc 66 i32 @f()
+	%26 = call cc 67 i32 @f()
+	%27 = call cc 68 i32 @f()
+	%28 = call cc 69 i32 @f()
+	%29 = call cc 70 i32 @f()
+	%30 = call cc 71 i32 @f()
+	%31 = call cc 72 i32 @f()
+	%32 = call cc 75 i32 @f()
+	%33 = call cc 76 i32 @f()
+	%34 = call cc 77 i32 @f()
+	%35 = call cc 78 i32 @f()
+	%36 = call cc 79 i32 @f()
+	%37 = call cc 80 i32 @f()
+	%38 = call cc 81 i32 @f()
+	%39 = call cc 82 i32 @f()
+	%40 = call cc 83 i32 @f()
+	%41 = call cc 84 i32 @f()
+	%42 = call cc 85 i32 @f()
+	%43 = call cc 86 i32 @f()
+	%44 = call cc 87 i32 @f()
+	%45 = call cc 88 i32 @f()
+	%46 = call cc 89 i32 @f()
+	%47 = call cc 90 i32 @f()
+	%48 = call cc 91 i32 @f()
+	%49 = call cc 92 i32 @f()
+	%50 = call ccc i32 @f()
+	%51 = call coldcc i32 @f()
+	%52 = call cxx_fast_tlscc i32 @f()
+	%53 = call fastcc i32 @f()
+	%54 = call ghccc i32 @f()
+	%55 = call hhvm_ccc i32 @f()
+	%56 = call hhvmcc i32 @f()
+	%57 = call intel_ocl_bicc i32 @f()
+	%58 = call msp430_intrcc i32 @f()
+	%59 = call preserve_allcc i32 @f()
+	%60 = call preserve_mostcc i32 @f()
+	%61 = call ptx_device i32 @f()
+	%62 = call ptx_kernel i32 @f()
+	%63 = call spir_func i32 @f()
+	%64 = call spir_kernel i32 @f()
+	%65 = call swiftcc i32 @f()
+	%66 = call webkit_jscc i32 @f()
+	%67 = call x86_64_sysvcc i32 @f()
+	%68 = call win64cc i32 @f()
+	%69 = call x86_fastcallcc i32 @f()
+	%70 = call x86_intrcc i32 @f()
+	%71 = call x86_regcallcc i32 @f()
+	%72 = call x86_stdcallcc i32 @f()
+	%73 = call x86_thiscallcc i32 @f()
+	%74 = call x86_vectorcallcc i32 @f()
+	ret void
+}
+
+
+define i32 ()* @h() {
+	ret i32 ()* @f
+}
+
+define void @call_7() {
+	; Return parameter attributes.
+	%1 = call "foo" "bar"="baz" align 8 dereferenceable(11) dereferenceable_or_null(22) inreg noalias i32 @f()
+	%2 = call nonnull i32 ()* @h()
+	%3 = call signext i32 @f()
+	%4 = call zeroext i32 @f()
+	ret void
+}
+
+define i32 @i(i32 %x, ...) {
+	ret i32 42
+}
+
+define i32 @call_8() {
+	; Callee with variadic arguments.
+	%result = call i32 (i32, ...) @i(i32 10, i32 20)
+	ret i32 %result
+}
+
+define i32 @call_9() {
+	; Callee from global identifier.
+	%result = call i32 @f()
+	ret i32 %result
+}
+
+define i32 @call_10(i32 ()* %callee) {
+	; Callee from function parameter.
+	%result = call i32 %callee()
+	ret i32 %result
+}
+
+declare void @j()
+
+define i32 @call_11() {
+	; Callee from bitcast expression.
+	%result = call i32 bitcast (void ()* @j to i32 (i32)*)(i32 42)
+	ret i32 %result
+}
+
+define i32 @call_12() {
+	%callee = bitcast void ()* @j to i32 (i32)*
+	; Callee from bitcast instruction.
+	%result = call i32 %callee(i32 42)
+	ret i32 %result
+}
+
+define i32 @call_13(i32 ()** %p) {
+	%callee = load i32 ()*, i32 ()** %p
+	; Callee from load instruction.
+	%result = call i32 %callee()
+	ret i32 %result
+}
+
+define i32 @k(i32 %x, i32 %y) {
+	ret i32 42
+}
+
+define i32 @call_14() {
+	; Multiple arguments.
+	%result = call i32 @k(i32 11, i32 22)
+	ret i32 %result
+}
+
+define i32 @call_15() {
+	; Function attributes.
+	%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
+}
+
+define void @l() {
+	ret void
+}
+
+define void @call_16() {
+	; Callee with void return type.
+	call void @l()
+	ret void
+}
+
+define i32 @call_17() {
+	; Metadata.
+	%result = call i32 @f(), !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+define double @m(double %x, double %y) {
+	ret double 42.0
+}
+
+define double @call_18() {
+	; Full instruction.
+	%result = tail call arcp fast ninf nnan nsz ccc "foo" "bar"="baz" align 8 dereferenceable(11) dereferenceable_or_null(22) inreg noalias double @m(double 11.0, double 22.0) "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, !foo !{!"bar"}, !baz !{!"qux"}
+	ret double %result
+}
+
+; ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @va_arg(i8* %p) {
+    va_arg i8* %p, float
+    ret void
+}
+
+; ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @landingpad() {
+    landingpad { i8*, i32 } cleanup
+    landingpad { i8*, i32 } catch i8* bitcast (i32* @g1 to i8*)
+    ret void
+}
+
+; ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @catchpad(i32* %arg1) {
+  catchpad:
+    %cs = catchswitch within none [label %catchpad] unwind to caller
+    catchpad within %cs []
+    ret void
+}
+
+; ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @cleanuppad() {
+  catchpad:
+    %cs = catchswitch within none [label %catchpad] unwind to caller
+    cleanuppad within none [i32 undef]
+    cleanuppad within %cs []
+    ret void
+}
+
+; ~~~ [ cleanupret ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @cleanupret() {
+  catchpad:
+    %cp = cleanuppad within none []
+    cleanupret from %cp unwind to caller
+    cleanupret from %cp unwind label %continue
+  continue:
+    ret void
+}
+
+; ~~~ [ invoke ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+declare void @llvm.donothing() nounwind readnone
+
+define void @invoke() {
+    normal:
+      invoke void @llvm.donothing() to label %normal unwind label %exception
+      invoke fastcc void @llvm.donothing() to label %normal unwind label %exception
+    exception:
+      ret void
+}
+
+attributes #0 = { "qux" }
diff --git a/tests/input/inst_vector.ll b/tests/input/inst_vector.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/inst_vector.ll
@@ -0,0 +1,43 @@
+; --- [ Vector instructions ] --------------------------------------------------
+
+; ~~~ [ extractelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @extractelement_1() {
+	; Plain instruction.
+	%result = extractelement <2 x i32> <i32 21, i32 42>, i32 1
+	ret i32 %result
+}
+
+define i32 @extractelement_2() {
+	; Metadata.
+	%result = extractelement <2 x i32> <i32 21, i32 42>, i32 1, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 %result
+}
+
+; ~~~ [ insertelement ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <2 x i32> @insertelement_1() {
+	; Plain instruction.
+	%result = insertelement <2 x i32> <i32 21, i32 42>, i32 42, i32 0
+	ret <2 x i32> %result
+}
+
+define <2 x i32> @insertelement_2() {
+	; Metadata.
+	%result = insertelement <2 x i32> <i32 21, i32 42>, i32 42, i32 0, !foo !{!"bar"}, !baz !{!"qux"}
+	ret <2 x i32> %result
+}
+
+; ~~~ [ shufflevector ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define <2 x i32> @shufflevector_1() {
+	; Plain instruction.
+	%result = shufflevector <2 x i32> <i32 21, i32 42>, <2 x i32> <i32 42, i32 84>, <2 x i32> <i32 1, i32 2>
+	ret <2 x i32> %result
+}
+
+define <2 x i32> @shufflevector_2() {
+	; Metadata.
+	%result = shufflevector <2 x i32> <i32 21, i32 42>, <2 x i32> <i32 42, i32 84>, <2 x i32> <i32 1, i32 2>, !foo !{!"bar"}, !baz !{!"qux"}
+	ret <2 x i32> %result
+}
diff --git a/tests/input/intrinsic.ll b/tests/input/intrinsic.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/intrinsic.ll
@@ -0,0 +1,12 @@
+; ModuleID = 'simple module'
+
+; Function Attrs: nounwind readonly
+declare double @llvm.sqrt.f64(double) #0
+
+define double @main() {
+entry:
+  %0 = call double @llvm.sqrt.f64(double 2.000000e+00)
+  ret double %0
+}
+
+attributes #0 = { nounwind readonly }
diff --git a/tests/input/loop.ll b/tests/input/loop.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/loop.ll
@@ -0,0 +1,18 @@
+define i32 @main() {
+; <label>:0
+	br label %1
+; <label>:1
+	%sum.0 = phi i32 [ 0, %0 ], [ %4, %5 ]
+	%i.0 = phi i32 [ 0, %0 ], [ %6, %5 ]
+	%2 = icmp slt i32 %i.0, 10
+	br i1 %2, label %3, label %7
+; <label>:3
+	%4 = add i32 %sum.0, %i.0
+	br label %5
+; <label>:5
+	%6 = add i32 %i.0, 1
+	br label %1
+; <label>:7
+	%8 = srem i32 %sum.0, 256
+	ret i32 %8
+}
diff --git a/tests/input/loopnest.ll b/tests/input/loopnest.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/loopnest.ll
@@ -0,0 +1,53 @@
+; ModuleID = 'simple module'
+
+declare i32 @foo(i32, i32)
+
+define i32 @main() {
+entry:
+  %0 = alloca i32
+  store i32 0, i32* %0
+  %1 = load i32, i32* %0
+  %2 = alloca i32
+  store i32 0, i32* %2
+  %3 = load i32, i32* %2
+  %4 = alloca i32
+  store i32 0, i32* %4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %5 = load i32, i32* %4
+  %6 = icmp ult i32 %5, 10
+  br i1 %6, label %for.loop, label %for.exit
+
+for.loop:                                         ; preds = %for.cond
+  %7 = load i32, i32* %4
+  %8 = alloca i32
+  store i32 0, i32* %8
+  br label %for.cond1
+
+for.inc:                                          ; preds = %for.exit1
+  %9 = add i32 %7, 1
+  store i32 %9, i32* %4
+  br label %for.cond
+
+for.exit:                                         ; preds = %for.cond
+  ret i32 0
+
+for.cond1:                                        ; preds = %for.inc1, %for.loop
+  %10 = load i32, i32* %8
+  %11 = icmp ult i32 %10, 20
+  br i1 %11, label %for.loop1, label %for.exit1
+
+for.loop1:                                        ; preds = %for.cond1
+  %12 = load i32, i32* %8
+  %13 = call i32 @foo(i32 %1, i32 %3)
+  br label %for.inc1
+
+for.inc1:                                         ; preds = %for.loop1
+  %14 = add i32 %12, 1
+  store i32 %14, i32* %8
+  br label %for.cond1
+
+for.exit1:                                        ; preds = %for.cond1
+  br label %for.inc
+}
diff --git a/tests/input/metadata.ll b/tests/input/metadata.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/metadata.ll
@@ -0,0 +1,47 @@
+declare !foo !0 !bar !{!"baz"} !qux !{!2} void @f1()
+
+define void @f2() !foo !0 !bar !{!"baz"} !qux !{!2} {
+	ret void
+}
+
+; --- [ Instruction metadata ] -------------------------------------------------
+
+define i32 @ret_3() {
+	%result = add i32 30, 12, !foo !{!"bar"}, !baz !{!"qux"}
+	ret i32 42, !foo !{!"bar"}, !baz !{!"qux"}
+}
+
+; --- [ Metadata definitions ] -------------------------------------------------
+
+; Empty named metadata definition.
+!foo = !{}
+
+; Plain named metadata definition.
+!bar = !{!0}
+
+; Multiple metadata IDs.
+!baz = !{!0, !1}
+
+; 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"}}
diff --git a/tests/input/module.ll b/tests/input/module.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/module.ll
@@ -0,0 +1,58 @@
+; === [ Modules ] ==============================================================
+
+; --- [ Source filename ] ------------------------------------------------------
+
+source_filename = "foo.c"
+
+; --- [ Target specifiers ] ----------------------------------------------------
+
+target datalayout = "e"
+target triple = "x86_64-unknown-linux"
+
+; --- [ Module-level inline assembly ] -----------------------------------------
+
+module asm "foo"
+
+; --- [ Type definitions ] -----------------------------------------------------
+
+%t1 = type i32
+
+%t2 = type opaque
+
+; --- [ Comdat definitions ] ---------------------------------------------------
+
+$com1 = comdat any
+$com2 = comdat exactmatch
+$com3 = comdat largest
+$com4 = comdat noduplicates
+$com5 = comdat samesize
+
+; --- [ Global variables ] -----------------------------------------------------
+
+@g1 = external global i32
+
+@g2 = global i32 0
+
+; --- [ Functions ] ------------------------------------------------------------
+
+declare void @exit(i32 %staus) #0
+
+declare i32 @printf(i8*, ...)
+
+define void @f1() {
+	ret void
+}
+
+define i32 @f2(i32 %x, i32 %y) {
+	ret i32 42
+}
+
+; --- [ Attribute group definitions ] ------------------------------------------
+
+attributes #0 = { noreturn }
+
+; --- [ Metadata definitions ] -------------------------------------------------
+
+!foo = !{!0}
+
+!0 = !{!"foo"}
diff --git a/tests/input/multiple.ll b/tests/input/multiple.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/multiple.ll
@@ -0,0 +1,16 @@
+; ModuleID = 'simple module'
+
+define i32 @foo(i32 %x) {
+entry:
+  %x.addr = alloca i32
+  store i32 %x, i32* %x.addr
+  %0 = load i32, i32* %x.addr
+  ret i32 %0
+}
+
+define i32 @bar(i32 %x) {
+entry:
+  %x.addr = alloca i32
+  store i32 %x, i32* %x.addr
+  ret i32 1000
+}
diff --git a/tests/input/names.ll b/tests/input/names.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/names.ll
@@ -0,0 +1,7 @@
+; ModuleID = 'simple module'
+
+define i32 @dashes-dollars$underscores_and.dots() {
+entry:
+  %local-dashes-dollars$underscores_and.dots = add i32 100, 23
+  ret i32 %local-dashes-dollars$underscores_and.dots
+}
diff --git a/tests/input/packed.ll b/tests/input/packed.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/packed.ll
@@ -0,0 +1,13 @@
+; ModuleID = 'tests/input/packed.ll'
+source_filename = "tests/input/packed.ll"
+
+@foo1 = external global <4 x float>
+@foo2 = external global <2 x i10>
+
+define void @main() {
+  store <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00>, <4 x float>* @foo1
+  store <2 x i10> <i10 4, i10 4>, <2 x i10>* @foo2
+  %l1 = load <4 x float>, <4 x float>* @foo1
+  %l2 = load <2 x i10>, <2 x i10>* @foo2
+  ret void
+}
diff --git a/tests/input/pair.ll b/tests/input/pair.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/pair.ll
@@ -0,0 +1,24 @@
+; ModuleID = 'simple module'
+
+@"%f" = global [3 x i8] c"%f\00"
+@"%i" = global [3 x i8] c"%i\00"
+
+declare i32 @printf(i8*, ...)
+
+declare i32 @printf1(i8*, ...)
+
+define i32 @main() {
+entry:
+  %0 = alloca { i32, float }
+  %1 = getelementptr inbounds { i32, float }, { i32, float }* %0, i32 0, i32 0
+  %2 = getelementptr inbounds { i32, float }, { i32, float }* %0, i32 0, i32 1
+  store i32 100, i32* %1
+  store float 2.000000e+02, float* %2
+  %3 = getelementptr inbounds { i32, float }, { i32, float }* %0, i32 0, i32 0
+  %4 = load i32, i32* %3
+  %5 = getelementptr inbounds { i32, float }, { i32, float }* %0, i32 0, i32 1
+  %6 = load float, float* %5
+  %7 = call i32 (i8*, ...) @printf1(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"%i", i32 0, i32 0), i32 %4)
+  %8 = call i32 (i8*, ...) @printf1(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"%f", i32 0, i32 0), float %6)
+  ret i32 %8
+}
diff --git a/tests/input/phi.ll b/tests/input/phi.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/phi.ll
@@ -0,0 +1,21 @@
+declare double @foo()
+
+declare double @bar()
+
+define double @baz(double %x) {
+entry:
+  %ifcond = fcmp one double %x, 0.000000e+00
+  br i1 %ifcond, label %then, label %else
+
+then:       ; preds = %entry
+  %calltmp = call double @foo()
+  br label %ifcont
+
+else:       ; preds = %entry
+  %calltmp1 = call double @bar()
+  br label %ifcont
+
+ifcont:     ; preds = %else, %then
+  %iftmp = phi double [ %calltmp, %then ], [ %calltmp1, %else ]
+  ret double %iftmp
+}
diff --git a/tests/input/prefix.ll b/tests/input/prefix.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/prefix.ll
@@ -0,0 +1,7 @@
+define void @main() prefix i32 123 {
+  ret void
+}
+
+define void @tuple() prefix {i32,i32} {i32 123, i32 321} {
+  ret void
+}
diff --git a/tests/input/printf.ll b/tests/input/printf.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/printf.ll
@@ -0,0 +1,11 @@
+; ModuleID = 'simple module'
+
+@"%i" = global [3 x i8] c"%i\00"
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main() {
+entry:
+  %0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"%i", i32 0, i32 0), i32 42)
+  ret i32 %0
+}
diff --git a/tests/input/rand.ll b/tests/input/rand.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/rand.ll
@@ -0,0 +1,13 @@
+@seed = global i32 0
+
+declare i32 @abs(i32 %x)
+
+define i32 @rand() {
+; <label>:0
+	%1 = load i32, i32* @seed
+	%2 = mul i32 %1, 22695477
+	%3 = add i32 %2, 1
+	store i32 %3, i32* @seed
+	%4 = call i32 @abs(i32 %3)
+	ret i32 %4
+}
diff --git a/tests/input/range.ll b/tests/input/range.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/range.ll
@@ -0,0 +1,28 @@
+; ModuleID = 'simple module'
+
+declare i32 @foo(i32)
+
+define i32 @rangeloop() {
+entry:
+  %0 = alloca i32
+  store i32 0, i32* %0
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %1 = load i32, i32* %0
+  %2 = icmp ult i32 %1, 100
+  br i1 %2, label %for.loop, label %for.exit
+
+for.loop:                                         ; preds = %for.cond
+  %3 = load i32, i32* %0
+  %4 = call i32 @foo(i32 %3)
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.loop
+  %5 = add i32 %3, 1
+  store i32 %5, i32* %0
+  br label %for.cond
+
+for.exit:                                         ; preds = %for.cond
+  ret i32 0
+}
diff --git a/tests/input/record.ll b/tests/input/record.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/record.ll
@@ -0,0 +1,9 @@
+; ModuleID = 'simple module'
+
+define i32 @main() {
+entry:
+  %0 = alloca { i32, float }
+  %1 = getelementptr inbounds { i32, float }, { i32, float }* %0, i32 0, i32 0
+  %2 = load i32, i32* %1
+  ret i32 %2
+}
diff --git a/tests/input/saxpy.ll b/tests/input/saxpy.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/saxpy.ll
@@ -0,0 +1,51 @@
+define void @SAXPY(i32* noalias nocapture %x, i32* noalias nocapture %y, i32 %a, i64 %i) {
+  %1 = getelementptr inbounds i32, i32* %x, i64 %i
+  %2 = load i32, i32* %1, align 4
+  %3 = mul nsw i32 %2, %a
+  %4 = getelementptr inbounds i32, i32* %y, i64 %i
+  %5 = load i32, i32* %4, align 4
+  %6 = add nsw i32 %3, %5
+  store i32 %6, i32* %1, align 4
+  %7 = add i64 %i, 1
+  %8 = getelementptr inbounds i32, i32* %x, i64 %7
+  %9 = load i32, i32* %8, align 4
+  %10 = mul nsw i32 %9, %a
+  %11 = getelementptr inbounds i32, i32* %y, i64 %7
+  %12 = load i32, i32* %11, align 4
+  %13 = add nsw i32 %10, %12
+  store i32 %13, i32* %8, align 4
+  %14 = add i64 %i, 2
+  %15 = getelementptr inbounds i32, i32* %x, i64 %14
+  %16 = load i32, i32* %15, align 4
+  %17 = mul nsw i32 %16, %a
+  %18 = getelementptr inbounds i32, i32* %y, i64 %14
+  %19 = load i32, i32* %18, align 4
+  %20 = add nsw i32 %17, %19
+  store i32 %20, i32* %15, align 4
+  %21 = add i64 %i, 3
+  %22 = getelementptr inbounds i32, i32* %x, i64 %21
+  %23 = load i32, i32* %22, align 4
+  %24 = mul nsw i32 %23, %a
+  %25 = getelementptr inbounds i32, i32* %y, i64 %21
+  %26 = load i32, i32* %25, align 4
+  %27 = add nsw i32 %24, %26
+  store i32 %27, i32* %22, align 4
+  ret void
+}
+
+; Make sure we don't crash on this one.
+define void @SAXPY_crash(i32* noalias nocapture %x, i32* noalias nocapture %y, i64 %i) {
+  %1 = add i64 %i, 1
+  %2 = getelementptr inbounds i32, i32* %x, i64 %1
+  %3 = getelementptr inbounds i32, i32* %y, i64 %1
+  %4 = load i32, i32* %3, align 4
+  %5 = add nsw i32 undef, %4
+  store i32 %5, i32* %2, align 4
+  %6 = add i64 %i, 2
+  %7 = getelementptr inbounds i32, i32* %x, i64 %6
+  %8 = getelementptr inbounds i32, i32* %y, i64 %6
+  %9 = load i32, i32* %8, align 4
+  %10 = add nsw i32 undef, %9
+  store i32 %10, i32* %7, align 4
+  ret void
+}
diff --git a/tests/input/simple.ll b/tests/input/simple.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/simple.ll
@@ -0,0 +1,8 @@
+; ModuleID = 'simple module'
+
+define i32 @foo(i32 %x) {
+entry:
+  %x.addr = alloca i32
+  store i32 %x, i32* %x.addr
+  ret i32 1001
+}
diff --git a/tests/input/tensorflow_blocks.ll b/tests/input/tensorflow_blocks.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/tensorflow_blocks.ll
@@ -0,0 +1,160 @@
+%"struct.mystruct" = type { i32, float, float*, float* }
+
+define i32 @main(%"struct.mystruct" *%structs) {
+  %1 = add i32 5, 3
+  %2 = add i32 %1, 7
+  %3 = fadd float 8.0, 3.0
+  %4 = fadd float %3, 9.0
+  %5 = fdiv float %4, %3
+  %6 = alloca i32, i32 1
+  %7 = load i32, i32 *%6
+  %8 = alloca float, i32 1
+  store float %5, float *%8
+  %9 = fcmp olt float %3, 4.0
+  %10 = icmp slt i32 %2, 4
+  %11 = trunc i32 %7 to i8
+  %12 = fadd double 8.0, 3.0
+  %13 = fptrunc double %12 to float
+  %14 = fpext float %13 to double
+  %15 = zext i32 %7 to i64
+  %16 = sext i32 %7 to i64
+  %17 = fptoui float %4 to i32
+  %18 = fptosi float %4 to i32
+  %19 = uitofp i32 %2 to float
+  %20 = sitofp i32 %2 to float
+  %21 = bitcast float *%8 to i32*
+  %22 = addrspacecast float* %8 to float addrspace(1) *
+  %23 = bitcast float %3 to i32
+  %24 = alloca %struct.mystruct, i32 1
+  %25 = load %struct.mystruct, %struct.mystruct* %24
+  %26 = extractvalue %struct.mystruct %25, 0
+  %27 = insertvalue %struct.mystruct %25, i32 4, 0
+  %28 = insertvalue %struct.mystruct %27, float 1.5, 1
+  %29 = getelementptr %struct.mystruct , %struct.mystruct *%24, i32 0, i32 0
+  %30 = getelementptr %struct.mystruct , %struct.mystruct *%24, i32 0, i32 1
+  %31 = icmp slt i32 %2, 4
+  %32 = select i1 %31, i32 21, i32 44
+
+  %33 = alloca i64, i32 1
+
+  store float %3, float *%8
+  store float %4, float *%8
+
+  store i64 %15, i64 *%33
+  store i64 %16, i64 *%33
+  store i32 %17, i32 *%6
+  store i32 %18, i32 *%6
+  store float %19, float *%8
+  store float %20, float *%8
+;  store i32 %21, i32 *%6
+ ; store i32 %22, i32 *%6
+  ;store i32 %24, i32 *%6
+
+  store %struct.mystruct %28, %struct.mystruct *%structs
+
+  store i32 %32, i32 *%6
+
+  ret i32 0
+}
+
+define float addrspace(1) *@someFunc(float addrspace(1) * %d1, float addrspace(1) * %v1) {
+    ret float addrspace(1) *%v1
+}
+
+define void @someKernel(float addrspace(1) * %d1, float addrspace(1) * %d2) {
+    %1 = alloca float addrspace(1)*, i32 1
+    %2 = load float addrspace(1) *, float addrspace(1) **%1
+    %3 = call float addrspace(1) * @someFunc(float addrspace(1) *%d1, float addrspace(1) *%2)
+    ret void
+}
+
+@mysharedmem = internal addrspace(3) global [8 x float] zeroinitializer, align 4
+
+define void @usesShared(float addrspace(1) *%d1) {
+    %1 = getelementptr inbounds [8 x float], [8 x float]* addrspacecast ([8 x float] addrspace(3) *@mysharedmem to [8 x float]*), i32 0
+    %2 = getelementptr inbounds [8 x float], [8 x float]* addrspacecast ([8 x float] addrspace(3)* @mysharedmem to [8 x float]*), i64 0, i64 0
+    %3 = getelementptr inbounds [8 x float], [8 x float]* addrspacecast ([8 x float] addrspace(3)* @mysharedmem to [8 x float]*), i64 0, i64 2
+    store float 4.0, float *%2
+    store float 3.0, float *%3
+    ret void
+}
+
+define float *@returnsPointer(float *%in) {
+    ret float * %in
+}
+
+define void @usesPointerFunction(float *%in) {
+    call float *@returnsPointer(float *%in)
+    ret void
+}
+
+define void @llvm.dbg.value(float *%foo, i64 %i1) {
+    ret void
+}
+
+define void @containsLlvmDebug(float *%d1) {
+    tail call void @llvm.dbg.value(float* %d1, i64 0)
+    ret void
+}
+
+define i32 @usestructs(%"struct.mystruct" *%structs) {
+  %1 = alloca %struct.mystruct, i32 1
+  %2 = load %struct.mystruct, %struct.mystruct* %1
+  %3 = getelementptr %struct.mystruct , %struct.mystruct *%1, i32 0, i32 1
+  %4 = alloca float, i32 1
+  %5 = load float, float *%4
+  store float %5, float *%3
+
+  %6 = insertvalue %struct.mystruct undef, i32 45, 0
+  %7 = insertvalue %struct.mystruct %6, float 3.5, 1
+  store %struct.mystruct %7, %struct.mystruct *%structs
+
+  %8 = extractvalue %struct.mystruct %7, 1
+  store float %8, float *%3
+
+  ret i32 0
+}
+
+define void @storefloat(float *%data) {
+  %1 = fadd float 5.0, 3.0
+  store float %1, float *%data
+  ret void
+}
+
+define void @test_bitcast(i32 *%data) {
+  %1 = fadd float 5.0, 3.0
+  %2 = bitcast float %1 to i32
+  store i32 %2, i32* %data
+  ret void
+}
+
+define void @test_ieee_doubles(double *%data) {
+  store double 0x43EFFE0000000000, double* %data
+  %1 = getelementptr inbounds double, double* %data, i64 0
+  store double 0x43DFFC0000000000, double* %1
+  %2 = getelementptr inbounds double, double* %data, i64 1
+  store double 0xFFF0000000000000, double* %2   ; -INFINITY
+  %3 = getelementptr inbounds double, double* %data, i64 2
+  store double 0x7FF0000000000000, double* %3   ; INFINITY
+  %4 = getelementptr inbounds double, double* %data, i64 3
+  store double 0xFFEFFFFFFFFFFFFF, double* %4   ; -INFINITY
+  ret void
+}
+
+%"class.tensorflow::random::Array" = type {
+  [4 x i32],
+  [4 x float]
+}
+
+define void @test_randomintarray(i32 *%data) {
+  %1 = alloca %"class.tensorflow::random::Array", i32 1
+  %2 = load %"class.tensorflow::random::Array", %"class.tensorflow::random::Array"* %1
+  %3 = extractvalue %"class.tensorflow::random::Array" %2, 0
+  %4 = extractvalue [4 x i32] %3, 0
+  %5 = extractvalue [4 x i32] %3, 1
+  %6 = extractvalue [4 x i32] %3, 2
+  %7 = add i32 %4, %5
+  %8 = add i32 %7, %6
+  store i32 %8, i32* %data
+  ret void
+}
diff --git a/tests/input/tensorflow_funcs.ll b/tests/input/tensorflow_funcs.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/tensorflow_funcs.ll
@@ -0,0 +1,145 @@
+define float @someFunc(float * %d1, float * %v1) {
+    ret float 3.0
+}
+
+define void @someKernel(float * %d1, float * %d2) {
+    %1 = alloca float *, i32 1
+    %2 = load float *, float **%1
+    %3 = call float @someFunc(float *%d1, float *%2)
+    ret void
+}
+
+define i32 @someFuncInts(i32 * %d1, i32 * %v1) {
+    ret i32 3
+}
+
+define void @someKernelInts(i32 * %d1, i32 * %d2) {
+    %1 = alloca i32 *, i32 1
+    %2 = load i32 *, i32 **%1
+    %3 = call i32 @someFuncInts(i32 *%d1, i32 *%2)
+    ret void
+}
+
+@mysharedmem = internal addrspace(3) global [8 x float] zeroinitializer, align 4
+@anothershared = internal addrspace(3) global [12 x i32] zeroinitializer, align 4
+
+define void @usesShared(float addrspace(1) *%d1) {
+    %1 = getelementptr inbounds [8 x float], [8 x float]* addrspacecast ([8 x float] addrspace(3) *@mysharedmem to [8 x float]*), i32 0, i32 3
+    %2 = alloca float, i32 1
+    %3 = load float, float* %2
+    store float %3, float * %1
+    ret void
+}
+
+define void @usesShared2(float addrspace(1) *%d1) {
+    %1 = getelementptr inbounds [8 x float], [8 x float]* addrspacecast ([8 x float] addrspace(3) *@mysharedmem to [8 x float]*), i32 0, i32 3
+    %2 = getelementptr inbounds [12 x i32], [12 x i32]* addrspacecast ([12 x i32] addrspace(3) *@anothershared to [12 x i32]*), i32 0, i32 7
+    %3 = alloca float, i32 1
+    %4 = alloca i32, i32 1
+    %5 = load float, float *%3
+    %6 = load i32, i32 *%4
+    store float %5, float *%1
+    store i32 %6, i32 *%2
+    ret void
+}
+
+define float *@returnsPointer(float *%in) {
+    ret float * %in
+}
+
+define void @usesPointerFunction(float *%in) {
+    call float *@returnsPointer(float *%in)
+    ret void
+}
+
+define float @returnsFloatConstant(float *%in) {
+    ret float 4.5
+}
+
+define void @testBranches_nophi(float *%d1) {
+label1:
+    %0 = fadd float 3.0, 4.0
+    %1 = alloca float, i32 1
+    store float %0, float *%1
+    br label %label2
+
+label2:
+    %2 = fadd float 5.0, 7.0
+    %3 = fcmp ogt float %2, 6.0
+    br i1 %3, label %label1, label %label2
+}
+
+define void @testBranches_onephi(float *%d1) {
+label1:
+    %0 = fadd float 3.0, 4.0
+    br label %label2
+
+label2:
+    %1 = phi float [%0, %label1], [%2, %label2]
+    %2 = fadd float %1, 7.0
+    %3 = fcmp ogt float %2, 6.0
+    br i1 %3, label %label1, label %label2
+}
+
+define void @testBranches_phifromfuture(float *%d1) {
+label1:
+    %0 = fadd float 3.0, 4.0
+    br label %label2
+
+label2:
+    %1 = phi float [%0, %label1], [%2, %label2], [%4, %label3]
+    %2 = fadd float %1, 7.0
+    %3 = fcmp ogt float %2, 6.0
+    br i1 %3, label %label1, label %label2
+
+label3:
+    %4 = fadd float 8.0, 2.0
+    br label %label2
+}
+
+define void @testBranches_phifromfloat(float *%d1) {
+label1:
+    %0 = fadd float 3.0, 4.0
+    br label %label2
+
+label2:
+    %1 = phi float [123.0, %label1], [%2, %label2], [%4, %label3]
+    %2 = fadd float %1, 7.0
+    %3 = fcmp ogt float %2, 6.0
+    br i1 %3, label %label1, label %label2
+
+label3:
+    %4 = fadd float 8.0, 2.0
+    br label %label2
+}
+
+; from test/cocl/multigpu.cu
+define void @multigpu_Z8getValuePf(float* nocapture %outdata) {
+  br label %2
+
+; <label>:1                                       ; preds = %2
+  %.lcssa = phi float [ %16, %2 ]
+  store float %.lcssa, float* %outdata
+  ret void
+
+; <label>:2                                       ; preds = %2, %0
+  %i.02 = phi i32 [ 1, %0 ], [ %17, %2 ]
+  %sum.01 = phi float [ 0.000000e+00, %0 ], [ %16, %2 ]
+  %3 = sext i32 %i.02 to i64
+  %4 = getelementptr inbounds float, float* %outdata, i64 %3
+  %5 = load float, float* %4
+  %6 = fadd float %sum.01, %5
+  %7 = add nuw nsw i32 %i.02, 1
+  %8 = sext i32 %7 to i64
+  %9 = getelementptr inbounds float, float* %outdata, i64 %8
+  %10 = load float, float* %9
+  %11 = fadd float %6, %10
+  %12 = add nsw i32 %i.02, 2
+  %13 = sext i32 %12 to i64
+  %14 = getelementptr inbounds float, float* %outdata, i64 %13
+  %15 = load float, float* %14
+  %16 = fadd float %11, %15
+  %17 = add nsw i32 %i.02, 3
+  %exitcond.2 = icmp eq i32 %17, 1024
+  br i1 %exitcond.2, label %1, label %2
+}
diff --git a/tests/input/tensorflow_kernel.ll b/tests/input/tensorflow_kernel.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/tensorflow_kernel.ll
@@ -0,0 +1,84 @@
+define float @someFunc(float * %d1, float *%v1) {
+    %1 = fadd float 3.0, 4.0
+    %2 = load float, float *%d1
+    %3 = getelementptr float , float *%d1, i32 3
+    store float %2, float *%3
+    ret float 4.5
+}
+
+define void @someKernel(float * %d1, float * %d2) {
+    %1 = alloca float *, i32 1
+    %2 = load float *, float **%1
+    %3 = call float @someFunc(float *%d1, float *%2)
+    %4 = call float @someFunc(float *%2, float *%d1)
+    %5 = call float @someFunc(float *%d1, float *%d1)
+    ret void
+}
+
+;  %29 = getelementptr %struct.mystruct , %struct.mystruct *%24, i32 0, i32 0
+
+define void @testBranches_phifromfuture(float *%d1) {
+label1:
+    %0 = fadd float 3.0, 4.0
+    br label %label2
+
+label2:
+    %1 = phi float [%0, %label1], [%2, %label2], [%4, %label3]
+    %2 = fadd float %1, 7.0
+    %3 = fcmp ogt float %2, 6.0
+    br i1 %3, label %label1, label %label2
+
+label3:
+    %4 = fadd float 8.0, 2.0
+    br label %label2
+}
+
+define float *@returnsPointer(float *%in) {
+    ret float * %in
+}
+
+define void @usesPointerFunction(float *%in) {
+    call float *@returnsPointer(float *%in)
+    %2 = alloca float, i32 1
+    call float *@returnsPointer(float *%2)
+    ret void
+}
+
+define void @returnsVoid(float *%in) {
+    store float 3.0, float * %in
+    ret void
+}
+
+define void @usesFunctionReturningVoid(float *%in) {
+    call void @returnsVoid(float *%in)
+    ret void
+}
+
+define void @mysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamea(float *%d) {
+    ret void
+}
+
+define void @mysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnameb(float *%d) {
+    ret void
+}
+
+define void @mysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamec(float *%d) {
+    call void @mysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamea(float *%d)
+    call void @mysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnamemysuperlongfunctionnameb(float *%d)
+    ret void
+}
+
+%"class.tensorflow::random::Array" = type { [4 x i32] }
+
+define void @test_randomintarray(i32 *%data) {
+  %1 = alloca %"class.tensorflow::random::Array", i32 1
+  %2 = load %"class.tensorflow::random::Array", %"class.tensorflow::random::Array"* %1
+  %3 = extractvalue %"class.tensorflow::random::Array" %2, 0
+  %4 = extractvalue [4 x i32] %3, 0
+  %5 = extractvalue [4 x i32] %3, 1
+  %6 = extractvalue [4 x i32] %3, 2
+  %7 = add i32 %4, %5
+  %8 = add i32 %7, %6
+  store i32 %8, i32* %data
+  ret void
+}
diff --git a/tests/input/tensorflow_types.ll b/tests/input/tensorflow_types.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/tensorflow_types.ll
@@ -0,0 +1,47 @@
+define i32 @type_return() {
+  ret i32 0
+}
+
+define i32 @add() {
+  %1 = add i32 5, 7
+  ret i32 %1
+}
+
+define void @float32() {
+  %1 = fadd float 1.25, 3.0
+  ret void
+}
+
+define void @float64() {
+  %1 = fadd double 1.25, 3.0
+  ret void
+}
+
+define void @pointer_float32() {
+    %1 = alloca float, i32 1
+    ret void
+}
+
+define void @pointer_globalpfloat() {
+    %1 = alloca float addrspace(1) *, i32 1
+    %2 = load float addrspace(1)*, float addrspace(1) ** %1
+    ret void
+}
+
+define void @array_int() {
+    %1 = alloca [4 x i32], i32 1
+    %2 = load [4 x i32], [4 x i32]* %1
+    ret void
+}
+
+%struct_mystruct = type { i32, float }
+
+define void @mystruct() {
+    %1 = alloca %struct_mystruct, i32 1
+    %2 = load %struct_mystruct, %struct_mystruct* %1
+    ret void
+}
+
+%"struct.mystruct" = type { i32, float, float*, float* }
+
+%"class.tensorflow::random::Array" = type { [4 x i32], [6 x float] }
diff --git a/tests/input/term.ll b/tests/input/term.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/term.ll
@@ -0,0 +1,137 @@
+; === [ Terminators ] ==========================================================
+
+; ~~~ [ ret ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @ret_1() {
+	; Plain terminator.
+	ret i32 42
+}
+
+define void @ret_2() {
+	; Void return
+	ret void
+}
+
+define i32 @ret_3() {
+	; Metadata.
+	ret i32 42, !foo !{!"bar"}, !baz !{!"qux"}
+}
+
+; ~~~ [ br ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @br_1() {
+	; Unconditional branch terminator.
+	br label %foo
+foo:
+	ret void
+}
+
+define void @br_2() {
+	; Metadata.
+	br label %foo, !foo !{!"bar"}, !baz !{!"qux"}
+foo:
+	ret void
+}
+
+define void @br_3(i1 %cond) {
+	; Conditional branch terminator.
+	br i1 %cond, label %foo, label %bar
+foo:
+	ret void
+bar:
+	ret void
+}
+
+define void @br_4(i1 %cond) {
+	; Metadata.
+	br i1 %cond, label %foo, label %bar, !foo !{!"bar"}, !baz !{!"qux"}
+foo:
+	ret void
+bar:
+	ret void
+}
+
+; ~~~ [ switch ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @switch_1() {
+	; Plain terminator.
+	switch i32 1, label %default [
+	]
+default:
+	ret void
+}
+
+define void @switch_2() {
+	; Multiple cases.
+	switch i32 2, label %default [
+		i32 1, label %case1
+		i32 2, label %case2
+		i32 3, label %case3
+	]
+default:
+	ret void
+case1:
+	ret void
+case2:
+	ret void
+case3:
+	ret void
+}
+
+define void @switch_3() {
+	; Metadata.
+	switch i32 2, label %default [
+		i32 1, label %case1
+		i32 2, label %case2
+		i32 3, label %case3
+	], !foo !{!"bar"}, !baz !{!"qux"}
+default:
+	ret void
+case1:
+	ret void
+case2:
+	ret void
+case3:
+	ret void
+}
+
+; ~~~ [ indirectbr ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define i32 @f() nounwind {
+  entry:
+    indirectbr i8* undef, []
+  exit:
+    indirectbr i8* undef, [label %exit]
+}
+
+; ~~~ [ invoke ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+; TODO: add test cases for invoke terminator.
+
+; ~~~ [ resume ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+; TODO: add test cases for resume terminator.
+
+; ~~~ [ catchswitch ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+; TODO: add test cases for catchswitch terminator.
+
+; ~~~ [ catchret ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+; TODO: add test cases for catchret terminator.
+
+; ~~~ [ cleanupret ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+; TODO: add test cases for cleanupret terminator.
+
+; ~~~ [ unreachable ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+define void @unreachable_1() {
+	; Plain terminator.
+	unreachable
+}
+
+define void @unreachable_2() {
+	; Metadata.
+	unreachable, !foo !{!"bar"}, !baz !{!"qux"}
+}
diff --git a/tests/input/type.ll b/tests/input/type.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/type.ll
@@ -0,0 +1,114 @@
+; === [ Types ] ================================================================
+
+; Void type
+;%t1 = type void
+
+; Function type
+%t2 = type i32 (i32)
+%t3 = type i32 (i32, i32)
+%t4 = type i32 (...)
+
+; Integer type
+%t5 = type i32
+
+; Floating-point type
+%t6 = type double
+
+; MMX type
+%t7 = type x86_mmx
+
+; Pointer type
+%t8 = type i32*
+%t9 = type i32 addrspace(2)*
+
+; Vector type
+%t10 = type <2 x i32>
+
+; Label type
+%t11 = type label
+
+; Token type
+%t12 = type token
+
+; Metadata type
+%t13 = type metadata
+
+; Array type
+%t14 = type [2 x i32]
+
+; Struct type
+%t15 = type {}
+%t16 = type { i32, double }
+
+; Packed struct type
+%t17 = type <{}>
+%t18 = type <{ i32, i8, i32 }>
+
+%t19 = type %t5
+
+; --- [ Void type ] ------------------------------------------------------------
+
+declare void @f1()
+
+; --- [ Function type ] --------------------------------------------------------
+
+; --- [ Integer type ] ---------------------------------------------------------
+
+declare i1 @f2()
+declare i2 @f3()
+declare i4 @f4()
+declare i8 @f5()
+declare i16 @f6()
+declare i32 @f7()
+declare i64 @f8()
+declare i128 @f9()
+
+; --- [ Floating-point type ] --------------------------------------------------
+
+declare half @f10()
+declare float @f11()
+declare double @f12()
+declare fp128 @f13()
+declare x86_fp80 @f14()
+declare ppc_fp128 @f15()
+
+; --- [ Pointer type ] ---------------------------------------------------------
+
+declare i8* @f16()
+
+; --- [ Vector type ] ----------------------------------------------------------
+
+declare <2 x i8> @f17()
+
+; --- [ Metadata type ] --------------------------------------------------------
+
+declare void @f19(metadata %x)
+
+; --- [ Array type ] -----------------------------------------------------------
+
+declare [2 x i32] @f20()
+
+; --- [ Struct type ] ----------------------------------------------------------
+
+declare {} @f21()
+declare { i32 } @f22()
+declare { i32, i8, [2 x i32], { i32, <2 x i8> } } @f23()
+declare <{}> @f24()
+declare <{ i32, i8, i32 }> @f25()
+
+; --- [ Named type ] -----------------------------------------------------------
+
+declare %t5 @f26()
+declare %t6 @f27()
+;declare %t7 @f28() ;; XXX: bug in llvm-hs?
+declare %t8 @f29()
+declare %t9 @f30()
+declare %t10 @f31()
+declare %t12 @f32()
+declare void @f33(%t13 %x)
+declare %t14 @f34()
+declare %t15 @f35()
+declare %t16 @f36()
+declare %t17 @f37()
+declare %t18 @f38()
+declare %t19 @f39()
diff --git a/tests/input/while.ll b/tests/input/while.ll
new file mode 100644
--- /dev/null
+++ b/tests/input/while.ll
@@ -0,0 +1,18 @@
+; ModuleID = 'simple module'
+
+declare i32 @foo()
+
+define i32 @whileloop() {
+entry:
+  br label %while.cond
+
+while.cond:                                       ; preds = %while.loop, %entry
+  br i1 true, label %while.loop, label %while.exit
+
+while.loop:                                       ; preds = %while.cond
+  %0 = call i32 @foo()
+  br label %while.cond
+
+while.exit:                                       ; preds = %while.cond
+  ret i32 0
+}
