-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtransform_replace_add.py
More file actions
71 lines (52 loc) · 1.93 KB
/
Copy pathtransform_replace_add.py
File metadata and controls
71 lines (52 loc) · 1.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""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()