@@ -72,7 +72,7 @@ pub trait Debug<'ink> {
72
72
/// function's stub as well as its interface (variables/parameters)
73
73
fn register_function < ' idx > (
74
74
& mut self ,
75
- index : & Index ,
75
+ indices : ( & Index , & LlvmTypedIndex < ' ink > ) ,
76
76
func : & FunctionContext < ' ink , ' idx > ,
77
77
return_type : Option < & ' idx DataType > ,
78
78
parent_function : Option < FunctionValue < ' ink > > ,
@@ -303,44 +303,110 @@ impl<'ink> DebugBuilder<'ink> {
303
303
. unwrap_or_else ( || self . compile_unit . get_file ( ) ) ;
304
304
305
305
let mut types = vec ! [ ] ;
306
- for ( element_index, ( member_name, dt, location) ) in index_types. into_iter ( ) . enumerate ( ) {
306
+ let mut last_offset_bits = 0 ;
307
+ let mut last_size_bits = 0 ;
308
+
309
+ for ( element_index, ( member_name, dt, location) ) in index_types. iter ( ) . enumerate ( ) {
307
310
let di_type = self . get_or_create_debug_type ( dt, index, types_index) ?;
308
311
309
- //Adjust the offset based on the field alignment
310
- let size = types_index
311
- . find_associated_type ( dt. get_name ( ) )
312
- . map ( |llvm_type| self . target_data . get_bit_size ( & llvm_type) )
312
+ // Get the size and alignment
313
+ let llvm_type = types_index. find_associated_type ( dt. get_name ( ) ) ;
314
+ let align_bits =
315
+ llvm_type. map ( |ty| self . target_data . get_preferred_alignment ( & ty) * 8 ) . unwrap_or ( 0 ) ;
316
+ let size_bits = llvm_type. map ( |ty| self . target_data . get_bit_size ( & ty) ) . unwrap_or ( 0 ) ;
317
+
318
+ // Get LLVM's calculated offset
319
+ let llvm_offset_bits = self
320
+ . target_data
321
+ . offset_of_element ( & struct_type, element_index as u32 )
322
+ . map ( |offset| offset * 8 )
313
323
. unwrap_or ( 0 ) ;
314
- //Offset in bits
315
- let offset =
316
- self . target_data . offset_of_element ( & struct_type, element_index as u32 ) . unwrap_or ( 0 ) * 8 ;
317
324
325
+ // Calculate the properly aligned offset based on the previous field
326
+ // and this field's alignment requirements
327
+ let offset_bits = if size_bits == 0 || ( last_size_bits == 0 && element_index > 0 ) {
328
+ // For zero-sized types, always use LLVM's offset directly
329
+ // This ensures they don't contribute to the overall layout calculation
330
+ // If the previous field was zero-sized, use LLVM's offset
331
+ // for proper alignment of fields after zero-sized types
332
+ llvm_offset_bits
333
+ } else {
334
+ let next_offset_bits: u64 = last_offset_bits + last_size_bits;
335
+
336
+ // Special handling based on alignment requirements:
337
+ // - Fields with alignment of 64 bits need to be explicitly aligned
338
+ // to their alignment boundary to prevent misaligned accesses
339
+ // - Fields with a lower alignment can use LLVM's natural layout
340
+ // This differentiation is crucial for correctly representing complex structures
341
+ // where some fields (like LWORD, LINT) need specific alignment while others (like BYTE, BOOL)
342
+ // can be packed more efficiently
343
+ if align_bits == 64 {
344
+ // For fields requiring special alignment (64 bit types),
345
+ // round up to the nearest alignment boundary
346
+ next_offset_bits. div_ceil ( align_bits as u64 ) * align_bits as u64
347
+ } else {
348
+ // For smaller fields fields (BYTE, BOOL, DINT), we still ensure we don't
349
+ // overlap with previous fields by using the maximum of our calculated offset
350
+ // and LLVM's calculated offset
351
+ std:: cmp:: max ( next_offset_bits, llvm_offset_bits)
352
+ }
353
+ } ;
354
+
355
+ // Update tracking variables for next field
356
+ last_offset_bits = offset_bits;
357
+ last_size_bits = size_bits;
358
+
359
+ // Create the member type with calculated offset
318
360
types. push (
319
361
self . debug_info
320
362
. create_member_type (
321
363
file. as_debug_info_scope ( ) ,
322
364
member_name,
323
365
file,
324
366
location. get_line_plus_one ( ) as u32 ,
325
- size ,
326
- 0 , // No set alignment
327
- offset ,
367
+ size_bits ,
368
+ align_bits ,
369
+ offset_bits ,
328
370
DIFlags :: PUBLIC ,
329
371
di_type. into ( ) ,
330
372
)
331
373
. as_type ( ) ,
332
374
) ;
333
375
}
334
376
335
- let size = self . target_data . get_bit_size ( & struct_type) ;
336
- //Create a struct type
377
+ // Calculate struct size based on the last field's offset + size, properly aligned
378
+ let llvm_size = self . target_data . get_bit_size ( & struct_type) ;
379
+ // Calculate our manual size based on adjusted offsets
380
+ let calculated_size = {
381
+ // Get struct alignment requirement (usually 8 bytes/64 bits for 64-bit architectures)
382
+ let struct_align_bits = self . target_data . get_preferred_alignment ( & struct_type) * 8 ;
383
+
384
+ // Calculate total size based on last field offset + size, rounded up to alignment
385
+ let last_field_end_bits = last_offset_bits + last_size_bits;
386
+ let aligned_size_bits =
387
+ last_field_end_bits. div_ceil ( struct_align_bits as u64 ) * struct_align_bits as u64 ;
388
+
389
+ // If our calculated size is larger than LLVM's, use ours
390
+ if aligned_size_bits > llvm_size {
391
+ log:: trace!(
392
+ "Struct {}: adjusted size from {} to {} bits due to field alignment" ,
393
+ name,
394
+ llvm_size,
395
+ aligned_size_bits
396
+ ) ;
397
+ aligned_size_bits
398
+ } else {
399
+ llvm_size
400
+ }
401
+ } ;
402
+
337
403
let struct_type = self . debug_info . create_struct_type (
338
404
file. as_debug_info_scope ( ) ,
339
405
name,
340
406
file,
341
407
location. get_line_plus_one ( ) as u32 ,
342
- size ,
343
- 0 , // No set alignment
408
+ calculated_size ,
409
+ self . target_data . get_preferred_alignment ( & struct_type ) * 8 ,
344
410
DIFlags :: PUBLIC ,
345
411
None ,
346
412
types. as_slice ( ) ,
@@ -364,20 +430,18 @@ impl<'ink> DebugBuilder<'ink> {
364
430
) -> Result < ( ) , Diagnostic > {
365
431
//find the inner type debug info
366
432
let inner_type = index. get_type ( inner_type) ?;
367
- //Find the dimenstions as ranges
433
+ //Find the dimensions as ranges
368
434
let subscript = dimensions
369
435
. iter ( )
370
436
. map ( |it| it. get_range_plus_one ( index) )
371
- //Convert to normal range
372
437
. collect :: < Result < Vec < Range < i64 > > , _ > > ( )
373
438
. map_err ( |err| Diagnostic :: codegen_error ( err, SourceLocation :: undefined ( ) ) ) ?;
374
439
let inner_type = self . get_or_create_debug_type ( inner_type, index, types_index) ?;
375
- let array_type = self . debug_info . create_array_type (
376
- inner_type. into ( ) ,
377
- size,
378
- 0 , //No set alignment
379
- subscript. as_slice ( ) ,
380
- ) ;
440
+ let llvm_type = types_index. get_associated_type ( name) ?;
441
+ let align_bits = self . target_data . get_preferred_alignment ( & llvm_type) * 8 ;
442
+ let array_type =
443
+ self . debug_info . create_array_type ( inner_type. into ( ) , size, align_bits, subscript. as_slice ( ) ) ;
444
+
381
445
self . register_concrete_type ( name, DebugType :: Composite ( array_type) ) ;
382
446
Ok ( ( ) )
383
447
}
@@ -392,11 +456,13 @@ impl<'ink> DebugBuilder<'ink> {
392
456
) -> Result < ( ) , Diagnostic > {
393
457
let inner_type = index. get_type ( inner_type) ?;
394
458
let inner_type = self . get_or_create_debug_type ( inner_type, index, types_index) ?;
459
+ let llvm_type = types_index. get_associated_type ( name) ?;
460
+ let align_bits = self . target_data . get_preferred_alignment ( & llvm_type) * 8 ;
395
461
let pointer_type = self . debug_info . create_pointer_type (
396
462
name,
397
463
inner_type. into ( ) ,
398
464
size,
399
- 0 , //No set alignment
465
+ align_bits ,
400
466
inkwell:: AddressSpace :: from ( ADDRESS_SPACE_GLOBAL ) ,
401
467
) ;
402
468
self . register_concrete_type ( name, DebugType :: Derived ( pointer_type) ) ;
@@ -438,14 +504,17 @@ impl<'ink> DebugBuilder<'ink> {
438
504
StringEncoding :: Utf16 => index. get_effective_type_or_void_by_name ( WCHAR_TYPE ) ,
439
505
} ;
440
506
let inner_type = self . get_or_create_debug_type ( inner_type, index, types_index) ?;
507
+ let llvm_type = types_index. get_associated_type ( name) ?;
508
+ let align_bits = self . target_data . get_preferred_alignment ( & llvm_type) * 8 ;
441
509
//Register an array
442
510
let array_type = self . debug_info . create_array_type (
443
511
inner_type. into ( ) ,
444
512
size,
445
- 0 , //No set alignment
513
+ align_bits ,
446
514
#[ allow( clippy:: single_range_in_vec_init) ]
447
515
& [ ( 0 ..length) ] ,
448
516
) ;
517
+
449
518
self . register_concrete_type ( name, DebugType :: Composite ( array_type) ) ;
450
519
Ok ( ( ) )
451
520
}
@@ -465,13 +534,15 @@ impl<'ink> DebugBuilder<'ink> {
465
534
. map ( |it| self . get_or_create_debug_file ( it) )
466
535
. unwrap_or_else ( || self . compile_unit . get_file ( ) ) ;
467
536
537
+ let llvm_type = types_index. get_associated_type ( name) ?;
538
+ let align_bits = self . target_data . get_preferred_alignment ( & llvm_type) * 8 ;
468
539
let typedef = self . debug_info . create_typedef (
469
540
inner_type. into ( ) ,
470
541
name,
471
542
file,
472
543
location. get_line_plus_one ( ) as u32 ,
473
544
file. as_debug_info_scope ( ) ,
474
- 0 , //No set alignment
545
+ align_bits ,
475
546
) ;
476
547
self . register_concrete_type ( name, DebugType :: Derived ( typedef) ) ;
477
548
@@ -547,6 +618,7 @@ impl<'ink> DebugBuilder<'ink> {
547
618
pou : & PouIndexEntry ,
548
619
func : & FunctionContext < ' ink , ' _ > ,
549
620
index : & Index ,
621
+ types_index : & LlvmTypedIndex < ' ink > ,
550
622
) {
551
623
let mut param_offset = 0 ;
552
624
//Register the return and local variables for debugging
@@ -555,7 +627,12 @@ impl<'ink> DebugBuilder<'ink> {
555
627
. iter ( )
556
628
. filter ( |it| it. is_local ( ) || it. is_temp ( ) || it. is_return ( ) )
557
629
{
558
- self . register_local_variable ( variable, 0 , func) ;
630
+ let align_bits = types_index
631
+ . get_associated_type ( & variable. data_type_name )
632
+ . map ( |it| self . target_data . get_preferred_alignment ( & it) )
633
+ . unwrap_or ( 0 )
634
+ * 8 ;
635
+ self . register_local_variable ( variable, align_bits, func) ;
559
636
}
560
637
561
638
let implementation = pou. find_implementation ( index) . expect ( "A POU will have an impl at this stage" ) ;
@@ -611,13 +688,14 @@ impl<'ink> Debug<'ink> for DebugBuilder<'ink> {
611
688
612
689
fn register_function < ' idx > (
613
690
& mut self ,
614
- index : & Index ,
691
+ indices : ( & Index , & LlvmTypedIndex < ' ink > ) ,
615
692
func : & FunctionContext < ' ink , ' idx > ,
616
693
return_type : Option < & ' idx DataType > ,
617
694
parent_function : Option < FunctionValue < ' ink > > ,
618
695
parameter_types : & [ & ' idx DataType ] ,
619
696
implementation_start : usize ,
620
697
) {
698
+ let ( index, types_index) = indices;
621
699
let pou = index. find_pou ( func. linking_context . get_call_name ( ) ) . expect ( "POU is available" ) ;
622
700
if matches ! ( pou. get_linkage( ) , LinkageType :: External ) || pou. get_location ( ) . is_internal ( ) {
623
701
return ;
@@ -635,7 +713,7 @@ impl<'ink> Debug<'ink> for DebugBuilder<'ink> {
635
713
let subprogram = self . create_function ( scope, pou, return_type, parameter_types, implementation_start) ;
636
714
func. function . set_subprogram ( subprogram) ;
637
715
//Create function parameters
638
- self . create_function_variables ( pou, func, index) ;
716
+ self . create_function_variables ( pou, func, index, types_index ) ;
639
717
}
640
718
641
719
fn register_debug_type < ' idx > (
@@ -720,7 +798,7 @@ impl<'ink> Debug<'ink> for DebugBuilder<'ink> {
720
798
false ,
721
799
None ,
722
800
None ,
723
- global_variable . get_alignment ( ) ,
801
+ 0 , // Global variable alignment does not need to be forced/set. See https://llvm.org/docs/LangRef.html#global-variables
724
802
) ;
725
803
let gv_metadata = debug_variable. as_metadata_value ( self . context ) ;
726
804
@@ -893,7 +971,7 @@ impl<'ink> Debug<'ink> for DebugBuilderEnum<'ink> {
893
971
894
972
fn register_function < ' idx > (
895
973
& mut self ,
896
- index : & Index ,
974
+ indices : ( & Index , & LlvmTypedIndex < ' ink > ) ,
897
975
func : & FunctionContext < ' ink , ' idx > ,
898
976
return_type : Option < & ' idx DataType > ,
899
977
parent_function : Option < FunctionValue < ' ink > > ,
@@ -903,7 +981,7 @@ impl<'ink> Debug<'ink> for DebugBuilderEnum<'ink> {
903
981
match self {
904
982
Self :: None | Self :: VariablesOnly ( ..) => { }
905
983
Self :: Full ( obj) => obj. register_function (
906
- index ,
984
+ indices ,
907
985
func,
908
986
return_type,
909
987
parent_function,
0 commit comments