File: debuginfo.ml

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (456 lines) | stat: -rw-r--r-- 19,978 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
(* RUN: rm -rf %t && mkdir -p %t && cp %s %t/debuginfo.ml && cp %S/Utils/Testsuite.ml %t/Testsuite.ml
 * RUN: %ocamlc -g -w +A -package llvm.all_backends -package llvm.target -package llvm.analysis -package llvm.debuginfo -I %t/ -linkpkg %t/Testsuite.ml %t/debuginfo.ml -o %t/executable
 * RUN: %t/executable | FileCheck %s
 * RUN: %ocamlopt -g -w +A -package llvm.all_backends -package llvm.target -package llvm.analysis -package llvm.debuginfo -I %t/ -linkpkg %t/Testsuite.ml %t/debuginfo.ml -o %t/executable
 * RUN: %t/executable | FileCheck %s
 * XFAIL: vg_leak
 *)

open Testsuite

let context = Llvm.global_context ()

let filename = "di_test_file"

let directory = "di_test_dir"

let module_name = "di_test_module"

let null_metadata = Llvm_debuginfo.llmetadata_null ()

let string_of_metadata md =
  Llvm.string_of_llvalue (Llvm.metadata_as_value context md)

let stdout_metadata md = Printf.printf "%s\n" (string_of_metadata md)

let prepare_target llmod =
  Llvm_all_backends.initialize ();
  let triple = Llvm_target.Target.default_triple () in
  let lltarget = Llvm_target.Target.by_triple triple in
  let llmachine = Llvm_target.TargetMachine.create ~triple lltarget in
  let lldly =
    Llvm_target.DataLayout.as_string
      (Llvm_target.TargetMachine.data_layout llmachine)
  in
  let _ = Llvm.set_target_triple triple llmod in
  let _ = Llvm.set_data_layout lldly llmod in
  ()

let new_module () =
  let m = Llvm.create_module context module_name in
  let () = prepare_target m in
  m

let test_get_module () =
  group "module_level_tests";
  let m = new_module () in
  let cur_ver = Llvm_debuginfo.debug_metadata_version () in
  insist (cur_ver > 0);
  let m_ver = Llvm_debuginfo.get_module_debug_metadata_version m in
  (* We haven't added any debug info to the module *)
  insist (m_ver = 0);
  let dibuilder = Llvm_debuginfo.dibuilder m in
  let di_version_key = "Debug Info Version" in
  let ver =
    Llvm.value_as_metadata @@ Llvm.const_int (Llvm.i32_type context) cur_ver
  in
  let () =
    Llvm.add_module_flag m Llvm.ModuleFlagBehavior.Warning di_version_key ver
  in
  let file_di =
    Llvm_debuginfo.dibuild_create_file dibuilder ~filename ~directory
  in
  stdout_metadata file_di;
  (* CHECK: [[FILE_PTR:<0x[0-9a-f]*>]] = !DIFile(filename: "di_test_file", directory: "di_test_dir")
  *)
  insist
    ( Llvm_debuginfo.di_file_get_filename ~file:file_di = filename
    && Llvm_debuginfo.di_file_get_directory ~file:file_di = directory );
  insist
    ( Llvm_debuginfo.get_metadata_kind file_di
    = Llvm_debuginfo.MetadataKind.DIFileMetadataKind );
  let cu_di =
    Llvm_debuginfo.dibuild_create_compile_unit dibuilder
      Llvm_debuginfo.DWARFSourceLanguageKind.C89 ~file_ref:file_di
      ~producer:"TestGen" ~is_optimized:false ~flags:"" ~runtime_ver:0
      ~split_name:"" Llvm_debuginfo.DWARFEmissionKind.LineTablesOnly ~dwoid:0
      ~di_inlining:false ~di_profiling:false ~sys_root:"" ~sdk:""
  in
  stdout_metadata cu_di;
  (* CHECK: [[CMPUNIT_PTR:<0x[0-9a-f]*>]] = distinct !DICompileUnit(language: DW_LANG_C89, file: [[FILE_PTR]], producer: "TestGen", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false)
  *)
  insist
    ( Llvm_debuginfo.get_metadata_kind cu_di
    = Llvm_debuginfo.MetadataKind.DICompileUnitMetadataKind );
  let m_di =
    Llvm_debuginfo.dibuild_create_module dibuilder ~parent_ref:cu_di
      ~name:module_name ~config_macros:"" ~include_path:"" ~sys_root:""
  in
  insist
    ( Llvm_debuginfo.get_metadata_kind m_di
    = Llvm_debuginfo.MetadataKind.DIModuleMetadataKind );
  insist (Llvm_debuginfo.get_module_debug_metadata_version m = cur_ver);
  stdout_metadata m_di;
  (* CHECK: [[MODULE_PTR:<0x[0-9a-f]*>]] = !DIModule(scope: null, name: "di_test_module")
  *)
  (m, dibuilder, file_di, m_di)

let flags_zero = Llvm_debuginfo.diflags_get Llvm_debuginfo.DIFlag.Zero

let int_ty_di bits dibuilder =
  Llvm_debuginfo.dibuild_create_basic_type dibuilder ~name:"int"
    ~size_in_bits:bits ~encoding:0x05
    (* llvm::dwarf::DW_ATE_signed *) flags_zero

let test_get_function m dibuilder file_di m_di =
  group "function_level_tests";

  (* Create a function of type "void foo (int)". *)
  let int_ty_di = int_ty_di 32 dibuilder in
  stdout_metadata int_ty_di;
  (* CHECK: [[INT32_PTR:<0x[0-9a-f]*>]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
  *)
  let param_types = [| null_metadata; int_ty_di |] in
  let fty_di =
    Llvm_debuginfo.dibuild_create_subroutine_type dibuilder ~file:file_di
      ~param_types flags_zero
  in
  insist
    ( Llvm_debuginfo.get_metadata_kind fty_di
    = Llvm_debuginfo.MetadataKind.DISubroutineTypeMetadataKind );
  (* To be able to print and verify the type array of the subroutine type,
   * since we have no way to access it from fty_di, we build it again. *)
  let fty_di_args =
    Llvm_debuginfo.dibuild_get_or_create_type_array dibuilder ~data:param_types
  in
  stdout_metadata fty_di_args;
  (* CHECK: [[FARGS_PTR:<0x[0-9a-f]*>]] = !{null, [[INT32_PTR]]}
  *)
  stdout_metadata fty_di;
  (* CHECK: [[SBRTNTY_PTR:<0x[0-9a-f]*>]] = !DISubroutineType(types: [[FARGS_PTR]])
  *)
  (* Let's create the LLVM-IR function now. *)
  let name = "tfun" in
  let fty =
    Llvm.function_type (Llvm.void_type context) [| Llvm.i32_type context |]
  in
  let f = Llvm.define_function name fty m in
  let f_di =
    Llvm_debuginfo.dibuild_create_function dibuilder ~scope:m_di ~name
      ~linkage_name:name ~file:file_di ~line_no:10 ~ty:fty_di
      ~is_local_to_unit:false ~is_definition:true ~scope_line:10
      ~flags:flags_zero ~is_optimized:false
  in
  stdout_metadata f_di;
  (* CHECK: [[SBPRG_PTR:<0x[0-9a-f]*>]] = distinct !DISubprogram(name: "tfun", linkageName: "tfun", scope: [[MODULE_PTR]], file: [[FILE_PTR]], line: 10, type: [[SBRTNTY_PTR]], scopeLine: 10, spFlags: DISPFlagDefinition, unit: [[CMPUNIT_PTR]])
  *)
  Llvm_debuginfo.set_subprogram f f_di;
  ( match Llvm_debuginfo.get_subprogram f with
  | Some f_di' -> insist (f_di = f_di')
  | None -> insist false );
  insist
    ( Llvm_debuginfo.get_metadata_kind f_di
    = Llvm_debuginfo.MetadataKind.DISubprogramMetadataKind );
  insist (Llvm_debuginfo.di_subprogram_get_line f_di = 10);
  (fty, f, f_di)

let test_bbinstr fty f f_di file_di dibuilder =
  group "basic_block and instructions tests";
  (* Create this pattern:
   *   if (arg0 != 0) {
   *      foo(arg0);
   *   }
   *   return;
   *)
  let arg0 = (Llvm.params f).(0) in
  let builder = Llvm.builder_at_end context (Llvm.entry_block f) in
  let zero = Llvm.const_int (Llvm.i32_type context) 0 in
  let cmpi = Llvm.build_icmp Llvm.Icmp.Ne zero arg0 "cmpi" builder in
  let truebb = Llvm.append_block context "truebb" f in
  let falsebb = Llvm.append_block context "falsebb" f in
  let _ = Llvm.build_cond_br cmpi truebb falsebb builder in
  let foodecl = Llvm.declare_function "foo" fty (Llvm.global_parent f) in
  let _ =
    Llvm.position_at_end truebb builder;
    let scope =
      Llvm_debuginfo.dibuild_create_lexical_block dibuilder ~scope:f_di
        ~file:file_di ~line:9 ~column:4
    in
    let file_of_f_di = Llvm_debuginfo.di_scope_get_file ~scope:f_di in
    let file_of_scope = Llvm_debuginfo.di_scope_get_file ~scope in
    insist
      ( match (file_of_f_di, file_of_scope) with
      | Some file_of_f_di', Some file_of_scope' ->
          file_of_f_di' = file_di && file_of_scope' = file_di
      | _ -> false );
    let foocall = Llvm.build_call fty foodecl [| arg0 |] "" builder in
    let foocall_loc =
      Llvm_debuginfo.dibuild_create_debug_location context ~line:10 ~column:12
        ~scope
    in
    Llvm_debuginfo.instr_set_debug_loc foocall (Some foocall_loc);
    insist
      ( match Llvm_debuginfo.instr_get_debug_loc foocall with
      | Some foocall_loc' -> foocall_loc' = foocall_loc
      | None -> false );
    stdout_metadata scope;
    (* CHECK: [[BLOCK_PTR:<0x[0-9a-f]*>]] = distinct !DILexicalBlock(scope: [[SBPRG_PTR]], file: [[FILE_PTR]], line: 9, column: 4)
     *)
    stdout_metadata foocall_loc;
    (* CHECK: !DILocation(line: 10, column: 12, scope: [[BLOCK_PTR]])
     *)
    insist
      ( Llvm_debuginfo.di_location_get_scope ~location:foocall_loc = scope
      && Llvm_debuginfo.di_location_get_line ~location:foocall_loc = 10
      && Llvm_debuginfo.di_location_get_column ~location:foocall_loc = 12 );
    insist
      ( Llvm_debuginfo.get_metadata_kind foocall_loc
        = Llvm_debuginfo.MetadataKind.DILocationMetadataKind
      && Llvm_debuginfo.get_metadata_kind scope
         = Llvm_debuginfo.MetadataKind.DILexicalBlockMetadataKind );
    Llvm.build_br falsebb builder
  in
  let _ =
    Llvm.position_at_end falsebb builder;
    Llvm.build_ret_void builder
  in
  (* Printf.printf "%s\n" (Llvm.string_of_llmodule (Llvm.global_parent f)); *)
  ()

let test_global_variable_expression dibuilder f_di m_di =
  group "global variable expression tests";
  let cexpr_di =
    Llvm_debuginfo.dibuild_create_constant_value_expression dibuilder 0
  in
  stdout_metadata cexpr_di;
  (* CHECK: [[DICEXPR:!DIExpression\(DW_OP_constu, 0, DW_OP_stack_value\)]]
   *)
  insist
    ( Llvm_debuginfo.get_metadata_kind cexpr_di
    = Llvm_debuginfo.MetadataKind.DIExpressionMetadataKind );
  let ty = int_ty_di 64 dibuilder in
  stdout_metadata ty;
  (* CHECK: [[INT64TY_PTR:<0x[0-9a-f]*>]] = !DIBasicType(name: "int", size: 64, encoding: DW_ATE_signed)
   *)
  let gvexpr_di =
    Llvm_debuginfo.dibuild_create_global_variable_expression dibuilder
      ~scope:m_di ~name:"my_global" ~linkage:"" ~file:f_di ~line:5 ~ty
      ~is_local_to_unit:true ~expr:cexpr_di ~decl:null_metadata ~align_in_bits:0
  in
  insist
    ( Llvm_debuginfo.get_metadata_kind gvexpr_di
    = Llvm_debuginfo.MetadataKind.DIGlobalVariableExpressionMetadataKind );
  ( match
      Llvm_debuginfo.di_global_variable_expression_get_variable gvexpr_di
    with
  | Some gvexpr_var_di ->
      insist
        ( Llvm_debuginfo.get_metadata_kind gvexpr_var_di
        = Llvm_debuginfo.MetadataKind.DIGlobalVariableMetadataKind );
      stdout_metadata gvexpr_var_di
      (* CHECK: [[GV_PTR:<0x[0-9a-f]*>]] = distinct !DIGlobalVariable(name: "my_global", scope: [[MODULE_PTR]], file: [[FILE_PTR]], line: 5, type: [[INT64TY_PTR]], isLocal: true, isDefinition: true)
       *)
  | None -> insist false );
  stdout_metadata gvexpr_di;
  (* CHECK: [[GVEXP_PTR:<0x[0-9a-f]*>]] = !DIGlobalVariableExpression(var: [[GV_PTR]], expr: [[DICEXPR]])
   *)
  ()

let test_variables f dibuilder file_di fun_di =
  let entry_term = Option.get @@ (Llvm.block_terminator (Llvm.entry_block f)) in
  group "Local and parameter variable tests";
  let ty = int_ty_di 64 dibuilder in
  stdout_metadata ty;
  (* CHECK: [[INT64TY_PTR:<0x[0-9a-f]*>]] = !DIBasicType(name: "int", size: 64, encoding: DW_ATE_signed)
  *)
  let auto_var =
    Llvm_debuginfo.dibuild_create_auto_variable dibuilder ~scope:fun_di
      ~name:"my_local" ~file:file_di ~line:10 ~ty
      ~always_preserve:false flags_zero ~align_in_bits:0
  in
  stdout_metadata auto_var;
  (* CHECK: [[LOCAL_VAR_PTR:<0x[0-9a-f]*>]] = !DILocalVariable(name: "my_local", scope: <{{0x[0-9a-f]*}}>, file: <{{0x[0-9a-f]*}}>, line: 10, type: [[INT64TY_PTR]])
  *)
  let builder = Llvm.builder_before context entry_term in
  let all = Llvm.build_alloca (Llvm.i64_type context)  "my_alloca" builder in
  let scope =
    Llvm_debuginfo.dibuild_create_lexical_block dibuilder ~scope:fun_di
      ~file:file_di ~line:9 ~column:4
  in
  let location =
    Llvm_debuginfo.dibuild_create_debug_location
    context ~line:10 ~column:12 ~scope
  in
  let vdi = Llvm_debuginfo.dibuild_insert_declare_before dibuilder ~storage:all
    ~var_info:auto_var ~expr:(Llvm_debuginfo.dibuild_expression dibuilder [||])
    ~location ~instr:entry_term
  in
  let () = Printf.printf "%s\n" (Llvm.string_of_llvalue vdi) in
  (* CHECK: call void @llvm.dbg.declare(metadata ptr %my_alloca, metadata {{![0-9]+}}, metadata !DIExpression()), !dbg {{\![0-9]+}}
  *)
  let arg0 = (Llvm.params f).(0) in
  let arg_var = Llvm_debuginfo.dibuild_create_parameter_variable dibuilder ~scope:fun_di
    ~name:"my_arg" ~argno:1 ~file:file_di ~line:10 ~ty
    ~always_preserve:false flags_zero
  in
  let argdi = Llvm_debuginfo.dibuild_insert_declare_before dibuilder ~storage:arg0
    ~var_info:arg_var ~expr:(Llvm_debuginfo.dibuild_expression dibuilder [||])
    ~location ~instr:entry_term
  in
  let () = Printf.printf "%s\n" (Llvm.string_of_llvalue argdi) in
  (* CHECK: call void @llvm.dbg.declare(metadata i32 %0, metadata {{![0-9]+}}, metadata !DIExpression()), !dbg {{\![0-9]+}}
  *)
  ()

let test_types dibuilder file_di m_di =
  group "type tests";
  let namespace_di =
    Llvm_debuginfo.dibuild_create_namespace dibuilder ~parent_ref:m_di
      ~name:"NameSpace1" ~export_symbols:false
  in
  stdout_metadata namespace_di;
  (* CHECK: [[NAMESPACE_PTR:<0x[0-9a-f]*>]] = !DINamespace(name: "NameSpace1", scope: [[MODULE_PTR]])
   *)
  let int64_ty_di = int_ty_di 64 dibuilder in
  let structty_args = [| int64_ty_di; int64_ty_di; int64_ty_di |] in
  let struct_ty_di =
    Llvm_debuginfo.dibuild_create_struct_type dibuilder ~scope:namespace_di
      ~name:"StructType1" ~file:file_di ~line_number:20 ~size_in_bits:192
      ~align_in_bits:0 flags_zero ~derived_from:null_metadata
      ~elements:structty_args Llvm_debuginfo.DWARFSourceLanguageKind.C89
      ~vtable_holder:null_metadata ~unique_id:"StructType1"
  in
  (* Since there's no way to fetch the element types which is now
   * a type array, we build that again for checking. *)
  let structty_di_eltypes =
    Llvm_debuginfo.dibuild_get_or_create_type_array dibuilder
      ~data:structty_args
  in
  stdout_metadata structty_di_eltypes;
  (* CHECK: [[STRUCTELT_PTR:<0x[0-9a-f]*>]] = !{[[INT64TY_PTR]], [[INT64TY_PTR]], [[INT64TY_PTR]]}
   *)
  stdout_metadata struct_ty_di;
  (* CHECK: [[STRUCT_PTR:<0x[0-9a-f]*>]] = !DICompositeType(tag: DW_TAG_structure_type, name: "StructType1", scope: [[NAMESPACE_PTR]], file: [[FILE_PTR]], line: 20, size: 192, elements: [[STRUCTELT_PTR]], identifier: "StructType1")
   *)
  insist
    ( Llvm_debuginfo.get_metadata_kind struct_ty_di
    = Llvm_debuginfo.MetadataKind.DICompositeTypeMetadataKind );
  let structptr_di =
    Llvm_debuginfo.dibuild_create_pointer_type dibuilder
      ~pointee_ty:struct_ty_di ~size_in_bits:192 ~align_in_bits:0
      ~address_space:0 ~name:""
  in
  stdout_metadata structptr_di;
  (* CHECK: [[STRUCTPTR_PTR:<0x[0-9a-f]*>]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[STRUCT_PTR]], size: 192, dwarfAddressSpace: 0)
   *)
  insist
    ( Llvm_debuginfo.get_metadata_kind structptr_di
    = Llvm_debuginfo.MetadataKind.DIDerivedTypeMetadataKind );
  let enumerator1 =
    Llvm_debuginfo.dibuild_create_enumerator dibuilder ~name:"Test_A" ~value:0
      ~is_unsigned:true
  in
  stdout_metadata enumerator1;
  (* CHECK: [[ENUMERATOR1_PTR:<0x[0-9a-f]*>]] = !DIEnumerator(name: "Test_A", value: 0, isUnsigned: true)
   *)
  let enumerator2 =
    Llvm_debuginfo.dibuild_create_enumerator dibuilder ~name:"Test_B" ~value:1
      ~is_unsigned:true
  in
  stdout_metadata enumerator2;
  (* CHECK: [[ENUMERATOR2_PTR:<0x[0-9a-f]*>]] = !DIEnumerator(name: "Test_B", value: 1, isUnsigned: true)
   *)
  let enumerator3 =
    Llvm_debuginfo.dibuild_create_enumerator dibuilder ~name:"Test_C" ~value:2
      ~is_unsigned:true
  in
  insist
    ( Llvm_debuginfo.get_metadata_kind enumerator1
      = Llvm_debuginfo.MetadataKind.DIEnumeratorMetadataKind
    && Llvm_debuginfo.get_metadata_kind enumerator2
       = Llvm_debuginfo.MetadataKind.DIEnumeratorMetadataKind
    && Llvm_debuginfo.get_metadata_kind enumerator3
       = Llvm_debuginfo.MetadataKind.DIEnumeratorMetadataKind );
  stdout_metadata enumerator3;
  (* CHECK: [[ENUMERATOR3_PTR:<0x[0-9a-f]*>]] = !DIEnumerator(name: "Test_C", value: 2, isUnsigned: true)
   *)
  let elements = [| enumerator1; enumerator2; enumerator3 |] in
  let enumeration_ty_di =
    Llvm_debuginfo.dibuild_create_enumeration_type dibuilder ~scope:namespace_di
      ~name:"EnumTest" ~file:file_di ~line_number:1 ~size_in_bits:64
      ~align_in_bits:0 ~elements ~class_ty:int64_ty_di
  in
  let elements_arr =
    Llvm_debuginfo.dibuild_get_or_create_array dibuilder ~data:elements
  in
  stdout_metadata elements_arr;
  (* CHECK: [[ELEMENTS_PTR:<0x[0-9a-f]*>]] = !{[[ENUMERATOR1_PTR]], [[ENUMERATOR2_PTR]], [[ENUMERATOR3_PTR]]}
   *)
  stdout_metadata enumeration_ty_di;
  (* CHECK: [[ENUMERATION_PTR:<0x[0-9a-f]*>]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "EnumTest", scope: [[NAMESPACE_PTR]], file: [[FILE_PTR]], line: 1, baseType: [[INT64TY_PTR]], size: 64, elements: [[ELEMENTS_PTR]])
   *)
  insist
    ( Llvm_debuginfo.get_metadata_kind enumeration_ty_di
    = Llvm_debuginfo.MetadataKind.DICompositeTypeMetadataKind );
  let int32_ty_di = int_ty_di 32 dibuilder in
  let class_mem1 =
    Llvm_debuginfo.dibuild_create_member_type dibuilder ~scope:namespace_di
      ~name:"Field1" ~file:file_di ~line_number:3 ~size_in_bits:32
      ~align_in_bits:0 ~offset_in_bits:0 flags_zero ~ty:int32_ty_di
  in
  stdout_metadata class_mem1;
  (* CHECK: [[MEMB1_PTR:<0x[0-9a-f]*>]] = !DIDerivedType(tag: DW_TAG_member, name: "Field1", scope: [[NAMESPACE_PTR]], file: [[FILE_PTR]], line: 3, baseType: [[INT32_PTR]], size: 32)
   *)
  insist (Llvm_debuginfo.di_type_get_name class_mem1 = "Field1");
  insist (Llvm_debuginfo.di_type_get_line class_mem1 = 3);
  let class_mem2 =
    Llvm_debuginfo.dibuild_create_member_type dibuilder ~scope:namespace_di
      ~name:"Field2" ~file:file_di ~line_number:4 ~size_in_bits:64
      ~align_in_bits:8 ~offset_in_bits:32 flags_zero ~ty:int64_ty_di
  in
  stdout_metadata class_mem2;
  (* CHECK: [[MEMB2_PTR:<0x[0-9a-f]*>]] = !DIDerivedType(tag: DW_TAG_member, name: "Field2", scope: [[NAMESPACE_PTR]], file: [[FILE_PTR]], line: 4, baseType: [[INT64TY_PTR]], size: 64, align: 8, offset: 32)
   *)
  insist (Llvm_debuginfo.di_type_get_offset_in_bits class_mem2 = 32);
  insist (Llvm_debuginfo.di_type_get_size_in_bits class_mem2 = 64);
  insist (Llvm_debuginfo.di_type_get_align_in_bits class_mem2 = 8);
  let class_elements = [| class_mem1; class_mem2 |] in
  insist
    ( Llvm_debuginfo.get_metadata_kind class_mem1
      = Llvm_debuginfo.MetadataKind.DIDerivedTypeMetadataKind
    && Llvm_debuginfo.get_metadata_kind class_mem2
       = Llvm_debuginfo.MetadataKind.DIDerivedTypeMetadataKind );
  stdout_metadata
    (Llvm_debuginfo.dibuild_get_or_create_type_array dibuilder
       ~data:class_elements);
  (* CHECK: [[CLASSMEM_PTRS:<0x[0-9a-f]*>]] = !{[[MEMB1_PTR]], [[MEMB2_PTR]]}
   *)
  let classty_di =
    Llvm_debuginfo.dibuild_create_class_type dibuilder ~scope:namespace_di
      ~name:"MyClass" ~file:file_di ~line_number:1 ~size_in_bits:96
      ~align_in_bits:0 ~offset_in_bits:0 flags_zero ~derived_from:null_metadata
      ~elements:class_elements ~vtable_holder:null_metadata
      ~template_params_node:null_metadata ~unique_identifier:"MyClass"
  in
  stdout_metadata classty_di;
  (* [[CLASS_PTR:<0x[0-9a-f]*>]] = !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass", scope: [[NAMESPACE_PTR]], file: [[FILE_PTR]], line: 1, size: 96, elements: [[CLASSMEM_PTRS]], identifier: "MyClass")
   *)
  insist
    ( Llvm_debuginfo.get_metadata_kind classty_di
    = Llvm_debuginfo.MetadataKind.DICompositeTypeMetadataKind );
  ()

let () =
  let m, dibuilder, file_di, m_di = test_get_module () in
  let fty, f, fun_di = test_get_function m dibuilder file_di m_di in
  let () = test_bbinstr fty f fun_di file_di dibuilder in
  let () = test_global_variable_expression dibuilder file_di m_di in
  let () = test_variables f dibuilder file_di fun_di in
  let () = test_types dibuilder file_di m_di in
  Llvm_debuginfo.dibuild_finalize dibuilder;
  ( match Llvm_analysis.verify_module m with
  | Some err ->
      prerr_endline ("Verification of module failed: " ^ err);
      exit_status := 1
  | None -> () );
  exit !exit_status