Skip to content

Commit a335757

Browse files
r41k0uclaude
andcommitted
Core: Fold a negated integer literal into a constant
-2 parses as USub(Constant 2), so u32 / -2 reached the divider as a mul-by-minus-one instruction rather than the constant clang folds it to. Fold it at the unary operator; the result is a literal like any other, with a literal's C rank, so the usual arithmetic conversions still make u32 / -2 an unsigned division by 0xFFFFFFFE. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BSDVsZH5NtoASyxB8FCtGU
1 parent d6cd5ac commit a335757

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

pythonbpf/expr/expr_pass.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,20 @@ def _handle_name_expr(
4848
raise SyntaxError(f"Undefined variable {expr.id}")
4949

5050

51+
def _int_literal(v: int):
52+
"""An integer literal: a 64-bit constant with C's literal rank as its
53+
descriptor, `int` if the value fits and `long long` otherwise."""
54+
lit_ty = IntTy(32, True) if -(1 << 31) <= v < (1 << 31) else IntTy(64, True)
55+
return ir.Constant(ir.IntType(64), v), lit_ty
56+
57+
5158
def _handle_constant_expr(compilation_context, builder, expr: ast.Constant):
5259
"""Handle ast.Constant expressions."""
5360
if isinstance(expr.value, int) or isinstance(expr.value, bool):
5461
# C gives a literal the type int if it fits, otherwise long long. That
5562
# rank is what makes `u32 / -2` an unsigned 32-bit division as in C.
5663
v = int(expr.value)
57-
lit_ty = IntTy(32, True) if -(1 << 31) <= v < (1 << 31) else IntTy(64, True)
58-
return ir.Constant(ir.IntType(64), v), lit_ty
64+
return _int_literal(v)
5965
elif isinstance(expr.value, str):
6066
str_name = f".str.{id(expr)}"
6167
str_bytes = expr.value.encode("utf-8") + b"\x00"
@@ -414,6 +420,10 @@ def _handle_unary_op(
414420
result = builder.xor(convert_to_bool(builder, operand), true_const)
415421
return result, ir.IntType(1)
416422
elif isinstance(expr.op, ast.USub):
423+
if isinstance(operand, ir.Constant) and isinstance(operand.constant, int):
424+
# -2 parses as USub(Constant 2); fold it so it is a literal like
425+
# any other, with a literal's C rank.
426+
return _int_literal(-operand.constant)
417427
# Negation happens in the operand's promoted type; for an unsigned
418428
# operand that is C's 2^N - x, which the narrowing produces.
419429
result_ty = usual_arithmetic_conversions(operand_ty, operand_ty)

0 commit comments

Comments
 (0)