Skip to content

Commit 80fcc04

Browse files
committed
Fix register() handling in IR generation. Update userspace code generation to reflect changes in struct_ops registration handling and ensure proper skeleton generation for eBPF programs.
1 parent 1fc1550 commit 80fcc04

File tree

4 files changed

+200
-93
lines changed

4 files changed

+200
-93
lines changed

src/ir_generator.ml

Lines changed: 111 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ let create_context ?(global_variables = []) symbol_table = {
9595
variable_types = Hashtbl.create 32;
9696
}
9797

98-
(** Register allocation *)
98+
(** Allocate a new register for intermediate values *)
9999
let allocate_register ctx =
100100
let reg = ctx.next_register in
101-
ctx.next_register <- ctx.next_register + 1;
101+
ctx.next_register <- reg + 1;
102102
reg
103103

104104
(** Get or allocate register for variable *)
@@ -543,36 +543,7 @@ let rec lower_expression ctx (expr : Ast.expr) =
543543
(* Check if this is a variable holding a function pointer or a direct function call *)
544544
if name = "register" then
545545
(* Special handling for register() builtin function *)
546-
if List.length arg_vals = 1 then
547-
let struct_arg = List.hd args in
548-
(* Handle impl block references specially *)
549-
let struct_val = match struct_arg.expr_desc with
550-
| Ast.Identifier impl_name ->
551-
(* Check if this is an impl block name in the symbol table *)
552-
(match Symbol_table.lookup_symbol ctx.symbol_table impl_name with
553-
| Some symbol ->
554-
(match symbol.kind with
555-
| Symbol_table.TypeDef _ ->
556-
(* This is an impl block - use the name directly *)
557-
let ir_type = IRStruct (impl_name, [], false) in
558-
make_ir_value (IRVariable impl_name) ir_type struct_arg.expr_pos
559-
| _ ->
560-
(* Regular variable - use normal processing *)
561-
lower_expression ctx struct_arg)
562-
| None ->
563-
(* Not found in symbol table - use normal processing *)
564-
lower_expression ctx struct_arg)
565-
| _ ->
566-
(* Not an identifier - use normal processing *)
567-
lower_expression ctx struct_arg
568-
in
569-
let result_reg = allocate_register ctx in
570-
let result_val = make_ir_value (IRRegister result_reg) IRU32 expr.expr_pos in
571-
let instr = make_ir_instruction (IRStructOpsRegister (result_val, struct_val)) expr.expr_pos in
572-
emit_instruction ctx instr;
573-
result_val
574-
else
575-
failwith "register() takes exactly one argument"
546+
handle_register_builtin_call ctx args expr.expr_pos ()
576547
else if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
577548
(* This is a variable holding a function pointer - use FunctionPointerCall *)
578549
let callee_val = lower_expression ctx callee_expr in
@@ -977,6 +948,45 @@ let rec lower_expression ctx (expr : Ast.expr) =
977948
generate_match_conditions arms;
978949
result_val
979950

951+
(** Helper function to handle register() builtin function calls *)
952+
and handle_register_builtin_call ctx args expr_pos ?target_register ?target_type () =
953+
if List.length args = 1 then
954+
let struct_arg = List.hd args in
955+
(* Handle impl block references specially *)
956+
let struct_val = match struct_arg.Ast.expr_desc with
957+
| Ast.Identifier impl_name ->
958+
(* Check if this is an impl block name in the symbol table *)
959+
(match Symbol_table.lookup_symbol ctx.symbol_table impl_name with
960+
| Some symbol ->
961+
(match symbol.kind with
962+
| Symbol_table.TypeDef _ ->
963+
(* This is an impl block - use the name directly *)
964+
let ir_type = IRStruct (impl_name, [], false) in
965+
make_ir_value (IRVariable impl_name) ir_type struct_arg.Ast.expr_pos
966+
| _ ->
967+
(* Regular variable - use normal processing *)
968+
lower_expression ctx struct_arg)
969+
| None ->
970+
(* Not found in symbol table - use normal processing *)
971+
lower_expression ctx struct_arg)
972+
| _ ->
973+
(* Not an identifier - use normal processing *)
974+
lower_expression ctx struct_arg
975+
in
976+
(* Create result value - use provided target or allocate new register *)
977+
let result_val = match target_register, target_type with
978+
| Some reg, Some typ -> make_ir_value (IRRegister reg) typ expr_pos
979+
| None, _ ->
980+
let result_reg = allocate_register ctx in
981+
make_ir_value (IRRegister result_reg) IRU32 expr_pos
982+
| Some reg, None -> make_ir_value (IRRegister reg) IRU32 expr_pos
983+
in
984+
let instr = make_ir_instruction (IRStructOpsRegister (result_val, struct_val)) expr_pos in
985+
emit_instruction ctx instr;
986+
result_val
987+
else
988+
failwith "register() takes exactly one argument"
989+
980990
(** Helper function to resolve type aliases and track them *)
981991
and resolve_type_alias ctx reg ast_type =
982992
match ast_type with
@@ -1021,22 +1031,29 @@ and resolve_declaration_type_and_init ctx reg typ_opt expr_opt =
10211031
(match expr.Ast.expr_desc with
10221032
| Ast.Call (callee_expr, args) ->
10231033
(* Handle function call that should return to the target register *)
1024-
let arg_vals = List.map (lower_expression ctx) args in
1025-
let result_val = make_ir_value (IRRegister reg) target_type expr.Ast.expr_pos in
1026-
let call_target = match callee_expr.Ast.expr_desc with
1027-
| Ast.Identifier name ->
1028-
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1029-
let callee_val = lower_expression ctx callee_expr in
1030-
FunctionPointerCall callee_val
1031-
else
1032-
DirectCall name
1033-
| _ ->
1034-
let callee_val = lower_expression ctx callee_expr in
1035-
FunctionPointerCall callee_val
1036-
in
1037-
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1038-
emit_instruction ctx instr;
1039-
(target_type, None)
1034+
(* Special handling for register() builtin function *)
1035+
(match callee_expr.Ast.expr_desc with
1036+
| Ast.Identifier "register" ->
1037+
let _ = handle_register_builtin_call ctx args expr.Ast.expr_pos ~target_register:reg ~target_type:target_type () in
1038+
(target_type, None)
1039+
| _ ->
1040+
(* Regular function call handling *)
1041+
let arg_vals = List.map (lower_expression ctx) args in
1042+
let result_val = make_ir_value (IRRegister reg) target_type expr.Ast.expr_pos in
1043+
let call_target = match callee_expr.Ast.expr_desc with
1044+
| Ast.Identifier name ->
1045+
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1046+
let callee_val = lower_expression ctx callee_expr in
1047+
FunctionPointerCall callee_val
1048+
else
1049+
DirectCall name
1050+
| _ ->
1051+
let callee_val = lower_expression ctx callee_expr in
1052+
FunctionPointerCall callee_val
1053+
in
1054+
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1055+
emit_instruction ctx instr;
1056+
(target_type, None))
10401057
| _ ->
10411058
(* Non-function call - use normal processing *)
10421059
let value = lower_expression ctx expr in
@@ -1050,22 +1067,29 @@ and resolve_declaration_type_and_init ctx reg typ_opt expr_opt =
10501067
| Some ast_type -> ast_type_to_ir_type_with_context ctx.symbol_table ast_type
10511068
| None -> IRU32 (* Default fallback *)
10521069
in
1053-
let arg_vals = List.map (lower_expression ctx) args in
1054-
let result_val = make_ir_value (IRRegister reg) inferred_type expr.Ast.expr_pos in
1055-
let call_target = match callee_expr.Ast.expr_desc with
1056-
| Ast.Identifier name ->
1057-
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1058-
let callee_val = lower_expression ctx callee_expr in
1059-
FunctionPointerCall callee_val
1060-
else
1061-
DirectCall name
1062-
| _ ->
1063-
let callee_val = lower_expression ctx callee_expr in
1064-
FunctionPointerCall callee_val
1065-
in
1066-
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1067-
emit_instruction ctx instr;
1068-
(inferred_type, None)
1070+
(* Special handling for register() builtin function *)
1071+
(match callee_expr.Ast.expr_desc with
1072+
| Ast.Identifier "register" ->
1073+
let _ = handle_register_builtin_call ctx args expr.Ast.expr_pos ~target_register:reg ~target_type:inferred_type () in
1074+
(inferred_type, None)
1075+
| _ ->
1076+
(* Regular function call handling *)
1077+
let arg_vals = List.map (lower_expression ctx) args in
1078+
let result_val = make_ir_value (IRRegister reg) inferred_type expr.Ast.expr_pos in
1079+
let call_target = match callee_expr.Ast.expr_desc with
1080+
| Ast.Identifier name ->
1081+
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1082+
let callee_val = lower_expression ctx callee_expr in
1083+
FunctionPointerCall callee_val
1084+
else
1085+
DirectCall name
1086+
| _ ->
1087+
let callee_val = lower_expression ctx callee_expr in
1088+
FunctionPointerCall callee_val
1089+
in
1090+
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1091+
emit_instruction ctx instr;
1092+
(inferred_type, None))
10691093
| _ ->
10701094
(* Non-function call - use normal processing *)
10711095
let value = lower_expression ctx expr in
@@ -1310,7 +1334,7 @@ and lower_statement ctx stmt =
13101334

13111335
(* Handle function call declarations elegantly by proper instruction ordering *)
13121336
(match expr_opt with
1313-
| Some expr when (match expr.Ast.expr_desc with Ast.Call _ -> true | _ -> false) ->
1337+
| Some expr when (match expr.expr_desc with Ast.Call _ -> true | _ -> false) ->
13141338
(* For function calls: emit declaration first, then call with assignment *)
13151339
let target_type = match typ_opt with
13161340
| Some ast_type -> resolve_type_alias ctx reg ast_type
@@ -1327,21 +1351,28 @@ and lower_statement ctx stmt =
13271351
(* Then emit function call as assignment *)
13281352
(match expr.Ast.expr_desc with
13291353
| Ast.Call (callee_expr, args) ->
1330-
let arg_vals = List.map (lower_expression ctx) args in
1331-
let result_val = make_ir_value (IRRegister reg) target_type expr.Ast.expr_pos in
1332-
let call_target = match callee_expr.Ast.expr_desc with
1333-
| Ast.Identifier name ->
1334-
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1335-
let callee_val = lower_expression ctx callee_expr in
1336-
FunctionPointerCall callee_val
1337-
else
1338-
DirectCall name
1339-
| _ ->
1340-
let callee_val = lower_expression ctx callee_expr in
1341-
FunctionPointerCall callee_val
1342-
in
1343-
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1344-
emit_instruction ctx instr
1354+
(* Special handling for register() builtin function *)
1355+
(match callee_expr.Ast.expr_desc with
1356+
| Ast.Identifier "register" ->
1357+
let _ = handle_register_builtin_call ctx args expr.Ast.expr_pos ~target_register:reg ~target_type:target_type () in
1358+
()
1359+
| _ ->
1360+
(* Regular function call handling *)
1361+
let arg_vals = List.map (lower_expression ctx) args in
1362+
let result_val = make_ir_value (IRRegister reg) target_type expr.Ast.expr_pos in
1363+
let call_target = match callee_expr.Ast.expr_desc with
1364+
| Ast.Identifier name ->
1365+
if Hashtbl.mem ctx.variables name || Hashtbl.mem ctx.function_parameters name then
1366+
let callee_val = lower_expression ctx callee_expr in
1367+
FunctionPointerCall callee_val
1368+
else
1369+
DirectCall name
1370+
| _ ->
1371+
let callee_val = lower_expression ctx callee_expr in
1372+
FunctionPointerCall callee_val
1373+
in
1374+
let instr = make_ir_instruction (IRCall (call_target, arg_vals, Some result_val)) expr.Ast.expr_pos in
1375+
emit_instruction ctx instr)
13451376
| _ -> ()) (* Shouldn't happen due to our guard *)
13461377
| _ ->
13471378
(* Non-function call declarations: use existing logic *)

src/stdlib.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ let builtin_functions = [
124124
description = "Register an impl block instance (struct_ops) with the kernel";
125125
is_variadic = false;
126126
ebpf_impl = ""; (* Not available in eBPF context *)
127-
userspace_impl = "bpf_map__attach_struct_ops";
127+
userspace_impl = ""; (* Use IRStructOpsRegister instruction instead *)
128128
kernel_impl = "";
129129
validate = Some validate_register_function;
130130
};

src/userspace_codegen.ml

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,17 +1720,24 @@ let rec generate_c_instruction_from_ir ctx instruction =
17201720
| IRStruct (name, _, _) -> name
17211721
| _ -> failwith "struct_ops register() argument must be an impl block instance")
17221722
in
1723-
(* Generate normal C code instead of statement expressions *)
1724-
sprintf {|if (!obj) {
1723+
(* Generate struct_ops registration code *)
1724+
sprintf {|({
1725+
if (!obj) {
17251726
fprintf(stderr, "eBPF skeleton not loaded for struct_ops registration\n");
1726-
return -1;
1727-
}
1728-
struct bpf_map *map = bpf_object__find_map_by_name(obj->obj, "%s");
1729-
if (!map) {
1730-
fprintf(stderr, "Failed to find struct_ops map '%s'\n");
1731-
return -1;
1727+
%s = -1;
1728+
} else {
1729+
struct bpf_map *map = bpf_object__find_map_by_name(obj->obj, "%s");
1730+
if (!map) {
1731+
fprintf(stderr, "Failed to find struct_ops map '%s'\n");
1732+
%s = -1;
1733+
} else {
1734+
struct bpf_link *link = bpf_map__attach_struct_ops(map);
1735+
%s = (link != NULL) ? 0 : -1;
1736+
if (link) bpf_link__destroy(link);
1737+
}
17321738
}
1733-
%s = bpf_map__attach_struct_ops(map);|} instance_name instance_name result_str
1739+
%s;
1740+
});|} result_str instance_name instance_name result_str result_str result_str
17341741

17351742
(** Generate C struct from IR struct definition *)
17361743
let generate_c_struct_from_ir ir_struct =
@@ -2343,7 +2350,8 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ty
23432350

23442351
(* Generate skeleton header include for standard libbpf skeleton *)
23452352
let base_name = Filename.remove_extension (Filename.basename source_filename) in
2346-
let skeleton_include = if ir_multi_prog.global_variables <> [] || uses_bpf_functions then
2353+
let needs_skeleton_header = ir_multi_prog.global_variables <> [] || uses_bpf_functions || ir_multi_prog.struct_ops_instances <> [] in
2354+
let skeleton_include = if needs_skeleton_header then
23472355
sprintf "#include \"%s.skel.h\"\n" base_name
23482356
else "" in
23492357

@@ -2380,8 +2388,9 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ty
23802388
(* Generate type alias definitions from AST *)
23812389
let type_alias_definitions = generate_type_alias_definitions_userspace_from_ast type_aliases in
23822390

2383-
(* Generate eBPF object instance *)
2384-
let skeleton_code = if ir_multi_prog.global_variables <> [] || uses_bpf_functions then
2391+
(* Generate eBPF object instance - also needed for struct_ops *)
2392+
let needs_skeleton = ir_multi_prog.global_variables <> [] || uses_bpf_functions || ir_multi_prog.struct_ops_instances <> [] in
2393+
let skeleton_code = if needs_skeleton then
23852394
sprintf "/* eBPF skeleton instance */\nstruct %s_ebpf *obj = NULL;\n" base_name
23862395
else "" in
23872396

0 commit comments

Comments
 (0)