Skip to content

Commit 8372111

Browse files
add basic IR gen strategy
1 parent eb4ee64 commit 8372111

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

pythonbpf/codegen.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,22 @@
1919
import tempfile
2020
from logging import Logger
2121
import logging
22+
import re
2223

2324
logger: Logger = logging.getLogger(__name__)
2425

2526
VERSION = "v0.1.4"
2627

2728

29+
def finalize_module(original_str):
30+
"""After all IR generation is complete, we monkey patch btf_ama attribute"""
31+
32+
# Create a string with applied transformation of btf_ama attribute addition to BTF struct field accesses.
33+
pattern = r'(@"llvm\.[^"]+:[^"]*" = external global i64, !llvm\.preserve\.access\.index ![0-9]+)'
34+
replacement = r'\1 "btf_ama"'
35+
return re.sub(pattern, replacement, original_str)
36+
37+
2838
def find_bpf_chunks(tree):
2939
"""Find all functions decorated with @bpf in the AST."""
3040
bpf_functions = []
@@ -121,10 +131,12 @@ def compile_to_ir(filename: str, output: str, loglevel=logging.INFO):
121131

122132
module.add_named_metadata("llvm.ident", [f"PythonBPF {VERSION}"])
123133

134+
module_string = finalize_module(str(module))
135+
124136
logger.info(f"IR written to {output}")
125137
with open(output, "w") as f:
126138
f.write(f'source_filename = "{filename}"\n')
127-
f.write(str(module))
139+
f.write(module_string)
128140
f.write("\n")
129141

130142
return output
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from pythonbpf.debuginfo import DebugInfoGenerator
2+
3+
4+
def debug_info_generation(struct, llvm_module):
5+
generator = DebugInfoGenerator(llvm_module)
6+
# this is sample debug info generation
7+
# i64type = generator.get_uint64_type()
8+
9+
struct_type = generator.create_struct_type([], 64 * 4, is_distinct=True)
10+
11+
global_var = generator.create_global_var_debug_info(
12+
struct.name, struct_type, is_local=False
13+
)
14+
15+
return global_var
Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import logging
2-
from pythonbpf.vmlinux_parser.dependency_handler import DependencyHandler
2+
from ..dependency_handler import DependencyHandler
3+
from .debug_info_gen import debug_info_generation
4+
from ..dependency_node import DependencyNode
5+
import llvmlite.ir as ir
36

47
logger = logging.getLogger(__name__)
58

69

710
class IRGenerator:
8-
def __init__(self, module, handler: DependencyHandler):
9-
self.module = module
11+
# get the assignments dict and add this stuff to it.
12+
def __init__(self, llvm_module, handler: DependencyHandler, assignment=None):
13+
self.llvm_module = llvm_module
1014
self.handler: DependencyHandler = handler
1115
self.generated: list[str] = []
1216
if not handler.is_ready:
@@ -15,22 +19,48 @@ def __init__(self, module, handler: DependencyHandler):
1519
)
1620
for struct in handler:
1721
self.struct_processor(struct)
18-
print()
1922

2023
def struct_processor(self, struct):
2124
if struct.name not in self.generated:
2225
print(f"IR generating for {struct.name}")
23-
print(f"Struct is {struct}")
2426
for dependency in struct.depends_on:
2527
if dependency not in self.generated:
2628
dep_node_from_dependency = self.handler[dependency]
2729
self.struct_processor(dep_node_from_dependency)
2830
self.generated.append(dependency)
29-
# write actual processor logic here after assuming all dependencies are resolved
31+
# actual processor logic here after assuming all dependencies are resolved
3032
# this part cannot yet resolve circular dependencies. Gets stuck on an infinite loop during that.
33+
self.gen_ir(struct)
3134
self.generated.append(struct.name)
3235

33-
def struct_name_generator(
34-
self,
35-
) -> None:
36-
pass
36+
def gen_ir(self, struct):
37+
# currently we generate all possible field accesses for CO-RE and put into the assignment table
38+
debug_info = debug_info_generation(struct, self.llvm_module)
39+
field_index = 0
40+
for field_name, field in struct.fields.items():
41+
# does not take arrays and similar types into consideration yet.
42+
field_co_re_name = self._struct_name_generator(struct, field, field_index)
43+
field_index += 1
44+
globvar = ir.GlobalVariable(
45+
self.llvm_module, ir.IntType(64), name=field_co_re_name
46+
)
47+
globvar.linkage = "external"
48+
globvar.set_metadata("llvm.preserve.access.index", debug_info)
49+
print()
50+
51+
def _struct_name_generator(
52+
self, struct: DependencyNode, field, field_index: int
53+
) -> str:
54+
if struct.name.startswith("struct_"):
55+
name = (
56+
"llvm."
57+
+ struct.name.removeprefix("struct_")
58+
+ f":0:{field.offset}"
59+
+ "$"
60+
+ f"0:{field_index}"
61+
)
62+
return name
63+
else:
64+
raise TypeError(
65+
"Name generation cannot occur due to type name not starting with struct"
66+
)

0 commit comments

Comments
 (0)