1
1
from llvmlite import ir
2
2
import ast
3
3
4
- from llvmlite import ir
5
- import ast
6
4
from logging import Logger
7
5
import logging
8
6
from .type_deducer import ctypes_to_ir
11
9
12
10
13
11
def emit_global (module : ir .Module , node , name ):
14
- print ("global" , node .returns .id )
12
+ logger .info (f"global identifier { name } processing" )
13
+ # TODO: below part is LLM generated check logic.
14
+ # deduce LLVM type from the annotated return
15
+ if not isinstance (node .returns , ast .Name ):
16
+ raise ValueError (f"Unsupported return annotation { ast .dump (node .returns )} " )
15
17
ty = ctypes_to_ir (node .returns .id )
16
18
19
+ # extract the return expression
20
+ ret_stmt = node .body [0 ]
21
+ if not isinstance (ret_stmt , ast .Return ) or ret_stmt .value is None :
22
+ raise ValueError (f"Global '{ name } ' has no valid return" )
23
+
24
+ init_val = ret_stmt .value
25
+
26
+ # simple constant like "return 0"
27
+ if isinstance (init_val , ast .Constant ):
28
+ llvm_init = ir .Constant (ty , init_val .value )
29
+
30
+ # variable reference like "return SOME_CONST"
31
+ elif isinstance (init_val , ast .Name ):
32
+ # you may need symbol resolution here, stub as 0 for now
33
+ raise ValueError (f"Name reference { init_val .id } not yet supported" )
34
+
35
+ # constructor call like "return c_int64(0)" or dataclass(...)
36
+ elif isinstance (init_val , ast .Call ):
37
+ if len (init_val .args ) == 1 and isinstance (init_val .args [0 ], ast .Constant ):
38
+ llvm_init = ir .Constant (ty , init_val .args [0 ].value )
39
+ else :
40
+ raise ValueError (f"Complex constructor not supported: { ast .dump (init_val )} " )
41
+
42
+ else :
43
+ raise ValueError (f"Unsupported return expr { ast .dump (init_val )} " )
44
+
17
45
gvar = ir .GlobalVariable (module , ty , name = name )
18
- gvar .initializer = ir . Constant ( ty , initial_value )
46
+ gvar .initializer = llvm_init
19
47
gvar .align = 8
20
48
gvar .linkage = "dso_local"
21
49
gvar .global_constant = False
@@ -24,11 +52,11 @@ def emit_global(module: ir.Module, node, name):
24
52
25
53
def globals_processing (tree , module ):
26
54
"""Process stuff decorated with @bpf and @bpfglobal except license and return the section name"""
27
- global_sym_tab = []
55
+ globals_sym_tab = []
28
56
29
57
for node in tree .body :
30
58
# Skip non-assignment and non-function nodes
31
- if not (isinstance (node , ( ast .FunctionDef , ast . AnnAssign , ast . Assign ) )):
59
+ if not (isinstance (node , ast .FunctionDef )):
32
60
continue
33
61
34
62
# Get the name based on node type
@@ -38,33 +66,31 @@ def globals_processing(tree, module):
38
66
continue
39
67
40
68
# Check for duplicate names
41
- if name in global_sym_tab :
69
+ if name in globals_sym_tab :
42
70
raise SyntaxError (f"ERROR: Global name '{ name } ' previously defined" )
43
71
else :
44
- global_sym_tab .append (name )
72
+ globals_sym_tab .append (name )
45
73
46
- # Process decorated functions
47
74
if isinstance (node , ast .FunctionDef ) and node .name != "LICENSE" :
48
- # Check decorators
49
75
decorators = [
50
76
dec .id for dec in node .decorator_list if isinstance (dec , ast .Name )
51
77
]
52
-
53
78
if "bpf" in decorators and "bpfglobal" in decorators :
54
79
if (
55
- len (node .body ) == 1
56
- and isinstance (node .body [0 ], ast .Return )
57
- and node .body [0 ].value is not None
58
- and isinstance (node .body [0 ].value , (ast .Constant , ast .Name ))
80
+ len (node .body ) == 1
81
+ and isinstance (node .body [0 ], ast .Return )
82
+ and node .body [0 ].value is not None
83
+ and isinstance (
84
+ node .body [0 ].value , (ast .Constant , ast .Name , ast .Call )
85
+ )
59
86
):
60
87
emit_global (module , node , name )
61
- return node .name
62
88
else :
63
- logger .info (f"Invalid global expression for '{ node .name } '" )
64
- return None
89
+ raise SyntaxError (f"ERROR: Invalid syntax for { name } global" )
65
90
66
91
return None
67
92
93
+
68
94
def emit_llvm_compiler_used (module : ir .Module , names : list [str ]):
69
95
"""
70
96
Emit the @llvm.compiler.used global given a list of function/global names.
@@ -94,12 +120,12 @@ def globals_list_creation(tree, module: ir.Module):
94
120
if isinstance (node , ast .FunctionDef ):
95
121
for dec in node .decorator_list :
96
122
if (
97
- isinstance (dec , ast .Call )
98
- and isinstance (dec .func , ast .Name )
99
- and dec .func .id == "section"
100
- and len (dec .args ) == 1
101
- and isinstance (dec .args [0 ], ast .Constant )
102
- and isinstance (dec .args [0 ].value , str )
123
+ isinstance (dec , ast .Call )
124
+ and isinstance (dec .func , ast .Name )
125
+ and dec .func .id == "section"
126
+ and len (dec .args ) == 1
127
+ and isinstance (dec .args [0 ], ast .Constant )
128
+ and isinstance (dec .args [0 ].value , str )
103
129
):
104
130
collected .append (node .name )
105
131
0 commit comments