11from llvmlite import ir
22import ast
33
4+ from logging import Logger
5+ import logging
6+ from .type_deducer import ctypes_to_ir
47
5- def emit_globals (module : ir .Module , names : list [str ]):
8+ logger : Logger = logging .getLogger (__name__ )
9+
10+ # TODO: this is going to be a huge fuck of a headache in the future.
11+ global_sym_tab = []
12+
13+
14+ def populate_global_symbol_table (tree , module : ir .Module ):
15+ for node in tree .body :
16+ if isinstance (node , ast .FunctionDef ):
17+ for dec in node .decorator_list :
18+ if (
19+ isinstance (dec , ast .Call )
20+ and isinstance (dec .func , ast .Name )
21+ and dec .func .id == "section"
22+ and len (dec .args ) == 1
23+ and isinstance (dec .args [0 ], ast .Constant )
24+ and isinstance (dec .args [0 ].value , str )
25+ ):
26+ global_sym_tab .append (node )
27+ elif isinstance (dec , ast .Name ) and dec .id == "bpfglobal" :
28+ global_sym_tab .append (node )
29+
30+ elif isinstance (dec , ast .Name ) and dec .id == "map" :
31+ global_sym_tab .append (node )
32+ return False
33+
34+
35+ def emit_global (module : ir .Module , node , name ):
36+ logger .info (f"global identifier { name } processing" )
37+ # deduce LLVM type from the annotated return
38+ if not isinstance (node .returns , ast .Name ):
39+ raise ValueError (f"Unsupported return annotation { ast .dump (node .returns )} " )
40+ ty = ctypes_to_ir (node .returns .id )
41+
42+ # extract the return expression
43+ # TODO: turn this return extractor into a generic function I can use everywhere.
44+ ret_stmt = node .body [0 ]
45+ if not isinstance (ret_stmt , ast .Return ) or ret_stmt .value is None :
46+ raise ValueError (f"Global '{ name } ' has no valid return" )
47+
48+ init_val = ret_stmt .value
49+
50+ # simple constant like "return 0"
51+ if isinstance (init_val , ast .Constant ):
52+ llvm_init = ir .Constant (ty , init_val .value )
53+
54+ # variable reference like "return SOME_CONST"
55+ elif isinstance (init_val , ast .Name ):
56+ # need symbol resolution here, stub as 0 for now
57+ raise ValueError (f"Name reference { init_val .id } not yet supported" )
58+
59+ # constructor call like "return c_int64(0)" or dataclass(...)
60+ elif isinstance (init_val , ast .Call ):
61+ if len (init_val .args ) >= 1 and isinstance (init_val .args [0 ], ast .Constant ):
62+ llvm_init = ir .Constant (ty , init_val .args [0 ].value )
63+ else :
64+ logger .info ("Defaulting to zero as no constant argument found" )
65+ llvm_init = ir .Constant (ty , 0 )
66+ else :
67+ raise ValueError (f"Unsupported return expr { ast .dump (init_val )} " )
68+
69+ gvar = ir .GlobalVariable (module , ty , name = name )
70+ gvar .initializer = llvm_init
71+ gvar .align = 8
72+ gvar .linkage = "dso_local"
73+ gvar .global_constant = False
74+ return gvar
75+
76+
77+ def globals_processing (tree , module ):
78+ """Process stuff decorated with @bpf and @bpfglobal except license and return the section name"""
79+ globals_sym_tab = []
80+
81+ for node in tree .body :
82+ # Skip non-assignment and non-function nodes
83+ if not (isinstance (node , ast .FunctionDef )):
84+ continue
85+
86+ # Get the name based on node type
87+ if isinstance (node , ast .FunctionDef ):
88+ name = node .name
89+ else :
90+ continue
91+
92+ # Check for duplicate names
93+ if name in globals_sym_tab :
94+ raise SyntaxError (f"ERROR: Global name '{ name } ' previously defined" )
95+ else :
96+ globals_sym_tab .append (name )
97+
98+ if isinstance (node , ast .FunctionDef ) and node .name != "LICENSE" :
99+ decorators = [
100+ dec .id for dec in node .decorator_list if isinstance (dec , ast .Name )
101+ ]
102+ if "bpf" in decorators and "bpfglobal" in decorators :
103+ if (
104+ len (node .body ) == 1
105+ and isinstance (node .body [0 ], ast .Return )
106+ and node .body [0 ].value is not None
107+ and isinstance (
108+ node .body [0 ].value , (ast .Constant , ast .Name , ast .Call )
109+ )
110+ ):
111+ emit_global (module , node , name )
112+ else :
113+ raise SyntaxError (f"ERROR: Invalid syntax for { name } global" )
114+
115+ return None
116+
117+
118+ def emit_llvm_compiler_used (module : ir .Module , names : list [str ]):
6119 """
7120 Emit the @llvm.compiler.used global given a list of function/global names.
8121 """
@@ -24,7 +137,7 @@ def emit_globals(module: ir.Module, names: list[str]):
24137 gv .section = "llvm.metadata"
25138
26139
27- def globals_processing (tree , module : ir .Module ):
140+ def globals_list_creation (tree , module : ir .Module ):
28141 collected = ["LICENSE" ]
29142
30143 for node in tree .body :
@@ -40,10 +153,11 @@ def globals_processing(tree, module: ir.Module):
40153 ):
41154 collected .append (node .name )
42155
43- elif isinstance (dec , ast .Name ) and dec .id == "bpfglobal" :
44- collected .append (node .name )
156+ # NOTE: all globals other than
157+ # elif isinstance(dec, ast.Name) and dec.id == "bpfglobal":
158+ # collected.append(node.name)
45159
46160 elif isinstance (dec , ast .Name ) and dec .id == "map" :
47161 collected .append (node .name )
48162
49- emit_globals (module , collected )
163+ emit_llvm_compiler_used (module , collected )
0 commit comments