Files
2026-05-12 17:55:29 +02:00

72 lines
1.9 KiB
Python

"""Parse LLVM IR and replace plain integer adds with equivalent subs.
The rewrite preserves both operands by converting ``x + y`` into
``x - (0 - y)``. Adds with ``nuw``/``nsw`` flags are intentionally left alone
because those flags carry poison semantics that this small example does not try
to reproduce.
This demonstrates the current transformation APIs:
- `inst.operands`
- `inst.replace_all_uses_with(...)`
- `inst.erase_from_parent()`
Run from the repository root with:
uv run python examples/transform_replace_add.py
"""
from __future__ import annotations
import textwrap
import llvm
INPUT_IR = """
define i32 @add_values(i32 %x, i32 %y) {
entry:
%sum = add i32 %x, %y
ret i32 %sum
}
"""
def transform(ir_text: str) -> str:
with llvm.create_context() as ctx:
with ctx.parse_ir(textwrap.dedent(ir_text).strip() + "\n") as mod:
for func in mod.functions:
if func.is_declaration:
continue
additions = [
inst
for bb in func.basic_blocks
for inst in bb.instructions
if (
inst.opcode == llvm.Opcode.Add
and not inst.nsw
and not inst.nuw
)
]
for inst in additions:
lhs, rhs = inst.operands
base_name = inst.name or "add"
with inst.create_builder() as builder:
neg_rhs = builder.neg(rhs, base_name + ".rhs.neg")
replacement = builder.sub(lhs, neg_rhs, base_name + ".repl")
inst.replace_all_uses_with(replacement)
inst.erase_from_parent()
assert mod.verify(), mod.verification_error
return str(mod)
def main() -> None:
print(transform(INPUT_IR), end="")
if __name__ == "__main__":
main()