From 745f59278f9664d2700380f62cf93f14e7ce6083 Mon Sep 17 00:00:00 2001 From: Pragyansh Chaturvedi Date: Tue, 7 Oct 2025 03:11:23 +0530 Subject: [PATCH] Move conditional logic to eval_expr, add _conver_to_bool, add passing bool test --- pythonbpf/expr_pass.py | 28 +++++++++++++++++++++++- pythonbpf/functions/functions_pass.py | 17 ++++++++++++-- tests/passing_tests/conditionals/bool.py | 21 ++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 tests/passing_tests/conditionals/bool.py diff --git a/pythonbpf/expr_pass.py b/pythonbpf/expr_pass.py index b037cc3..79ff4bb 100644 --- a/pythonbpf/expr_pass.py +++ b/pythonbpf/expr_pass.py @@ -131,9 +131,35 @@ def _handle_ctypes_call( return val +def _handle_comparator(builder, op, lhs, rhs): + """Handle comparison operations.""" + + # NOTE: For now assume same types + + comparison_ops = { + ast.Eq: "==", + ast.NotEq: "!=", + ast.Lt: "<", + ast.LtE: "<=", + ast.Gt: ">", + ast.GtE: ">=", + } + + if type(op) not in comparison_ops: + logger.error(f"Unsupported comparison operator: {type(op)}") + return None + + predicate = comparison_ops[type(op)] + result = builder.icmp_signed(predicate, lhs, rhs) + logger.debug(f"Comparison result: {result}") + return result, ir.IntType(1) + + def _handle_compare( func, module, builder, cond, local_sym_tab, map_sym_tab, structs_sym_tab=None ): + """Handle ast.Compare expressions.""" + if len(cond.ops) != 1 or len(cond.comparators) != 1: logger.error("Only single comparisons are supported") return None @@ -162,7 +188,7 @@ def _handle_compare( lhs, _ = lhs rhs, _ = rhs - return None + return _handle_comparator(builder, cond.ops[0], lhs, rhs) def eval_expr( diff --git a/pythonbpf/functions/functions_pass.py b/pythonbpf/functions/functions_pass.py index f31d48e..7463f54 100644 --- a/pythonbpf/functions/functions_pass.py +++ b/pythonbpf/functions/functions_pass.py @@ -240,12 +240,25 @@ def handle_assign( logger.info("Unsupported assignment value type") +def _convert_to_bool(builder, val): + if val.type == ir.IntType(1): + return val + if isinstance(val.type, ir.PointerType): + zero = ir.Constant(val.type, None) + else: + zero = ir.Constant(val.type, 0) + return builder.icmp_signed("!=", val, zero) + + def handle_cond(func, module, builder, cond, local_sym_tab, map_sym_tab): + if True: + val = eval_expr(func, module, builder, cond, local_sym_tab, map_sym_tab)[0] + return _convert_to_bool(builder, val) if isinstance(cond, ast.Constant): if isinstance(cond.value, bool) or isinstance(cond.value, int): - return ir.Constant(ir.IntType(1), int(bool(cond.value))) + return ir.Constant(ir.IntType(1), int(cond.value)) else: - logger.info("Unsupported constant type in condition") + raise ValueError("Unsupported constant type in condition") return None elif isinstance(cond, ast.Name): if cond.id in local_sym_tab: diff --git a/tests/passing_tests/conditionals/bool.py b/tests/passing_tests/conditionals/bool.py new file mode 100644 index 0000000..341fa46 --- /dev/null +++ b/tests/passing_tests/conditionals/bool.py @@ -0,0 +1,21 @@ +from pythonbpf import bpf, section, bpfglobal, compile +from ctypes import c_void_p, c_int64 + + +@bpf +@section("tracepoint/syscalls/sys_enter_execve") +def hello_world(ctx: c_void_p) -> c_int64: + if True: + print("Hello, World!") + else: + print("Goodbye, World!") + return + + +@bpf +@bpfglobal +def LICENSE() -> str: + return "GPL" + + +compile()