@@ -17,41 +17,108 @@ def deref_to_depth(func, builder, val, target_depth):
1717
1818 # dereference with null check
1919 pointee_type = cur_type .pointee
20- null_check_block = builder .block
21- not_null_block = func .append_basic_block (name = f"deref_not_null_{ depth } " )
22- merge_block = func .append_basic_block (name = f"deref_merge_{ depth } " )
2320
24- null_ptr = ir .Constant (cur_type , None )
25- is_not_null = builder .icmp_signed ("!=" , cur_val , null_ptr )
26- logger .debug (f"Inserted null check for pointer at depth { depth } " )
21+ def load_op (builder , ptr ):
22+ return builder .load (ptr )
2723
28- builder .cbranch (is_not_null , not_null_block , merge_block )
24+ cur_val = _null_checked_operation (
25+ func , builder , cur_val , load_op , pointee_type , f"deref_{ depth } "
26+ )
27+ cur_type = pointee_type
28+ logger .debug (f"Dereferenced to depth { depth } , type: { pointee_type } " )
29+ return cur_val
2930
30- builder .position_at_end (not_null_block )
31- dereferenced_val = builder .load (cur_val )
32- logger .debug (f"Dereferenced to depth { depth - 1 } , type: { pointee_type } " )
33- builder .branch (merge_block )
3431
35- builder .position_at_end (merge_block )
36- phi = builder .phi (pointee_type , name = f"deref_result_{ depth } " )
32+ def _null_checked_operation (func , builder , ptr , operation , result_type , name_prefix ):
33+ """
34+ Generic null-checked operation on a pointer.
35+ """
36+ curr_block = builder .block
37+ not_null_block = func .append_basic_block (name = f"{ name_prefix } _not_null" )
38+ merge_block = func .append_basic_block (name = f"{ name_prefix } _merge" )
3739
38- zero_value = (
39- ir .Constant (pointee_type , 0 )
40- if isinstance (pointee_type , ir .IntType )
41- else ir .Constant (pointee_type , None )
42- )
43- phi .add_incoming (zero_value , null_check_block )
40+ # Null check
41+ null_ptr = ir .Constant (ptr .type , None )
42+ is_not_null = builder .icmp_signed ("!=" , ptr , null_ptr )
43+ builder .cbranch (is_not_null , not_null_block , merge_block )
4444
45- phi .add_incoming (dereferenced_val , not_null_block )
45+ # Not-null path: execute operation
46+ builder .position_at_end (not_null_block )
47+ result = operation (builder , ptr )
48+ not_null_after = builder .block
49+ builder .branch (merge_block )
4650
47- # Continue with phi result
48- cur_val = phi
49- cur_type = pointee_type
50- return cur_val
51+ # Merge with PHI
52+ builder .position_at_end (merge_block )
53+ phi = builder .phi (result_type , name = f"{ name_prefix } _result" )
54+
55+ # Null fallback value
56+ if isinstance (result_type , ir .IntType ):
57+ null_val = ir .Constant (result_type , 0 )
58+ elif isinstance (result_type , ir .PointerType ):
59+ null_val = ir .Constant (result_type , None )
60+ else :
61+ null_val = ir .Constant (result_type , ir .Undefined )
62+
63+ phi .add_incoming (null_val , curr_block )
64+ phi .add_incoming (result , not_null_after )
65+
66+ return phi
5167
5268
53- def deref_struct_ptr (
54- func , builder , struct_ptr , struct_metadata , field_name , structs_sym_tab
69+ def access_struct_field (
70+ builder , var_ptr , var_type , var_metadata , field_name , structs_sym_tab , func = None
5571):
56- """Dereference a pointer to a struct type."""
57- return deref_to_depth (func , builder , struct_ptr , 1 )
72+ """
73+ Access a struct field - automatically returns value or pointer based on field type.
74+ """
75+ # Get struct metadata
76+ metadata = (
77+ structs_sym_tab .get (var_metadata )
78+ if isinstance (var_metadata , str )
79+ else var_metadata
80+ )
81+ if not metadata or field_name not in metadata .fields :
82+ raise ValueError (f"Field '{ field_name } ' not found in struct" )
83+
84+ field_type = metadata .field_type (field_name )
85+ is_ptr_to_struct = isinstance (var_type , ir .PointerType ) and isinstance (
86+ var_metadata , str
87+ )
88+
89+ # Get struct pointer
90+ struct_ptr = builder .load (var_ptr ) if is_ptr_to_struct else var_ptr
91+
92+ # Decide: load value or return pointer?
93+ should_load = not isinstance (field_type , ir .ArrayType )
94+
95+ # Define the field access operation
96+ def field_access_op (builder , ptr ):
97+ typed_ptr = builder .bitcast (ptr , metadata .ir_type .as_pointer ())
98+ field_ptr = metadata .gep (builder , typed_ptr , field_name )
99+ return builder .load (field_ptr ) if should_load else field_ptr
100+
101+ # Handle null check for pointer-to-struct
102+ if is_ptr_to_struct :
103+ if func is None :
104+ raise ValueError ("func required for null-safe struct pointer access" )
105+
106+ if should_load :
107+ result_type = field_type
108+ else :
109+ result_type = field_type .as_pointer ()
110+
111+ result = _null_checked_operation (
112+ func ,
113+ builder ,
114+ struct_ptr ,
115+ field_access_op ,
116+ result_type ,
117+ f"field_{ field_name } " ,
118+ )
119+ return result , field_type
120+
121+ # No null check needed
122+ field_ptr = metadata .gep (builder , struct_ptr , field_name )
123+ result = builder .load (field_ptr ) if should_load else field_ptr
124+ return result , field_type
0 commit comments