mirror of
https://github.com/LLVMParty/llvm-nanobind
synced 2026-06-21 13:43:38 +00:00
193 lines
7.5 KiB
Python
Executable File
193 lines
7.5 KiB
Python
Executable File
#!/usr/bin/env -S uv run
|
|
"""
|
|
Test: test_struct
|
|
Integration test: Struct manipulation with Point type
|
|
|
|
Python equivalent of tests/test_struct.cpp
|
|
Must produce identical output to the C++ version.
|
|
"""
|
|
|
|
import llvm
|
|
|
|
|
|
def main():
|
|
with llvm.create_context() as ctx:
|
|
with ctx.create_module("test_struct") as mod:
|
|
i32 = ctx.types.i32
|
|
void_ty = ctx.types.void
|
|
ptr = ctx.types.ptr
|
|
|
|
# ==========================================
|
|
# Define Point struct: { i32 x, i32 y }
|
|
# ==========================================
|
|
point_ty = ctx.types.opaque_struct("Point")
|
|
point_ty.set_body([i32, i32], packed=False)
|
|
|
|
# ==========================================
|
|
# Function: void point_init(Point* p, i32 x, i32 y)
|
|
# ==========================================
|
|
init_ty = ctx.types.function(void_ty, [ptr, i32, i32])
|
|
init_func = mod.add_function("point_init", init_ty)
|
|
|
|
p = init_func.get_param(0)
|
|
x = init_func.get_param(1)
|
|
y = init_func.get_param(2)
|
|
p.name = "p"
|
|
x.name = "x"
|
|
y.name = "y"
|
|
|
|
init_entry = init_func.append_basic_block("entry")
|
|
|
|
with init_entry.create_builder() as builder:
|
|
# Store x to p->x (field 0)
|
|
x_ptr = builder.struct_gep(point_ty, p, 0, "x_ptr")
|
|
builder.store(x, x_ptr)
|
|
|
|
# Store y to p->y (field 1)
|
|
y_ptr = builder.struct_gep(point_ty, p, 1, "y_ptr")
|
|
builder.store(y, y_ptr)
|
|
|
|
builder.ret_void()
|
|
|
|
# ==========================================
|
|
# Function: void point_add(Point* a, Point* b, Point* result)
|
|
# ==========================================
|
|
add_ty = ctx.types.function(void_ty, [ptr, ptr, ptr])
|
|
add_func = mod.add_function("point_add", add_ty)
|
|
|
|
a = add_func.get_param(0)
|
|
b = add_func.get_param(1)
|
|
result = add_func.get_param(2)
|
|
a.name = "a"
|
|
b.name = "b"
|
|
result.name = "result"
|
|
|
|
add_entry = add_func.append_basic_block("entry")
|
|
builder.position_at_end(add_entry)
|
|
|
|
# Load a->x and a->y
|
|
a_x_ptr = builder.struct_gep(point_ty, a, 0, "a_x_ptr")
|
|
a_y_ptr = builder.struct_gep(point_ty, a, 1, "a_y_ptr")
|
|
a_x = builder.load(i32, a_x_ptr, "a_x")
|
|
a_y = builder.load(i32, a_y_ptr, "a_y")
|
|
|
|
# Load b->x and b->y
|
|
b_x_ptr = builder.struct_gep(point_ty, b, 0, "b_x_ptr")
|
|
b_y_ptr = builder.struct_gep(point_ty, b, 1, "b_y_ptr")
|
|
b_x = builder.load(i32, b_x_ptr, "b_x")
|
|
b_y = builder.load(i32, b_y_ptr, "b_y")
|
|
|
|
# Compute sum
|
|
sum_x = builder.add(a_x, b_x, "sum_x")
|
|
sum_y = builder.add(a_y, b_y, "sum_y")
|
|
|
|
# Store to result
|
|
result_x_ptr = builder.struct_gep(point_ty, result, 0, "result_x_ptr")
|
|
result_y_ptr = builder.struct_gep(point_ty, result, 1, "result_y_ptr")
|
|
builder.store(sum_x, result_x_ptr)
|
|
builder.store(sum_y, result_y_ptr)
|
|
|
|
builder.ret_void()
|
|
|
|
# ==========================================
|
|
# Function: i32 point_manhattan_distance(Point* p)
|
|
# Returns |x| + |y| (simplified: just x + y for demo)
|
|
# ==========================================
|
|
dist_ty = ctx.types.function(i32, [ptr])
|
|
dist_func = mod.add_function("point_manhattan", dist_ty)
|
|
|
|
dist_p = dist_func.get_param(0)
|
|
dist_p.name = "p"
|
|
|
|
dist_entry = dist_func.append_basic_block("entry")
|
|
builder.position_at_end(dist_entry)
|
|
|
|
px_ptr = builder.struct_gep(point_ty, dist_p, 0, "px_ptr")
|
|
py_ptr = builder.struct_gep(point_ty, dist_p, 1, "py_ptr")
|
|
px = builder.load(i32, px_ptr, "px")
|
|
py = builder.load(i32, py_ptr, "py")
|
|
dist = builder.add(px, py, "dist")
|
|
builder.ret(dist)
|
|
|
|
# ==========================================
|
|
# Function: i32 test_points()
|
|
# Creates two points, adds them, returns manhattan distance
|
|
# ==========================================
|
|
test_ty = ctx.types.function(i32, [])
|
|
test_func = mod.add_function("test_points", test_ty)
|
|
|
|
test_entry = test_func.append_basic_block("entry")
|
|
builder.position_at_end(test_entry)
|
|
|
|
# Allocate three Points
|
|
p1 = builder.alloca(point_ty, "p1")
|
|
p2 = builder.alloca(point_ty, "p2")
|
|
p3 = builder.alloca(point_ty, "p3")
|
|
|
|
# Initialize p1 = (3, 4)
|
|
init_args1 = [p1, i32.constant(3), i32.constant(4)]
|
|
builder.call(init_ty, init_func, init_args1, "")
|
|
|
|
# Initialize p2 = (1, 2)
|
|
init_args2 = [p2, i32.constant(1), i32.constant(2)]
|
|
builder.call(init_ty, init_func, init_args2, "")
|
|
|
|
# Add p1 + p2 -> p3
|
|
add_args = [p1, p2, p3]
|
|
builder.call(add_ty, add_func, add_args, "")
|
|
|
|
# Get manhattan distance of p3
|
|
dist_args = [p3]
|
|
final_dist = builder.call(dist_ty, dist_func, dist_args, "final_dist")
|
|
|
|
builder.ret(final_dist)
|
|
|
|
# ==========================================
|
|
# Global constant Point
|
|
# ==========================================
|
|
origin_vals = [i32.constant(0), i32.constant(0)]
|
|
origin_const = point_ty.named_struct_const(origin_vals)
|
|
origin_global = mod.add_global(point_ty, "origin")
|
|
origin_global.initializer = origin_const
|
|
origin_global.is_global_constant = True
|
|
|
|
# Verify module
|
|
if not mod.verify():
|
|
print(f"; Verification failed: {mod.verification_error}")
|
|
return 1
|
|
|
|
# Print diagnostic comments
|
|
print("; Test: test_struct")
|
|
print("; Integration test: Point struct manipulation")
|
|
print(";")
|
|
print("; Struct definition:")
|
|
print("; %Point = type { i32, i32 } ; x, y fields")
|
|
print(";")
|
|
print("; Functions:")
|
|
print("; point_init(Point*, i32, i32) -> void")
|
|
print("; point_add(Point*, Point*, Point*) -> void")
|
|
print("; point_manhattan(Point*) -> i32")
|
|
print("; test_points() -> i32")
|
|
print(";")
|
|
print("; test_points creates:")
|
|
print("; p1 = (3, 4)")
|
|
print("; p2 = (1, 2)")
|
|
print("; p3 = p1 + p2 = (4, 6)")
|
|
print("; returns manhattan(p3) = 4 + 6 = 10")
|
|
print(";")
|
|
print("; Struct type info:")
|
|
print(f"; name: {point_ty.struct_name}")
|
|
print(f"; num elements: {point_ty.struct_element_count}")
|
|
print(f"; is packed: {'yes' if point_ty.is_packed_struct else 'no'}")
|
|
print(f"; is opaque: {'yes' if point_ty.is_opaque_struct else 'no'}")
|
|
print()
|
|
|
|
# Print module IR
|
|
print(mod.to_string(), end="")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit(main())
|