mirror of
https://github.com/LLVMParty/llvm-nanobind
synced 2026-06-21 13:43:38 +00:00
230 lines
8.3 KiB
C++
230 lines
8.3 KiB
C++
/**
|
|
* Test: test_struct
|
|
* Integration test: Struct manipulation with Point type
|
|
*
|
|
* This test creates a named struct type and demonstrates:
|
|
* - Named struct creation and body setting
|
|
* - Struct GEP for field access
|
|
* - Load/store of struct fields
|
|
* - A complete point_add function
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <llvm-c/Analysis.h>
|
|
#include <llvm-c/Core.h>
|
|
|
|
int main() {
|
|
LLVMContextRef ctx = LLVMContextCreate();
|
|
LLVMModuleRef mod = LLVMModuleCreateWithNameInContext("test_struct", ctx);
|
|
|
|
LLVMTypeRef i32 = LLVMInt32TypeInContext(ctx);
|
|
LLVMTypeRef void_ty = LLVMVoidTypeInContext(ctx);
|
|
LLVMTypeRef ptr = LLVMPointerTypeInContext(ctx, 0);
|
|
|
|
LLVMBuilderRef builder = LLVMCreateBuilderInContext(ctx);
|
|
|
|
// ==========================================
|
|
// Define Point struct: { i32 x, i32 y }
|
|
// ==========================================
|
|
LLVMTypeRef point_ty = LLVMStructCreateNamed(ctx, "Point");
|
|
LLVMTypeRef point_fields[] = {i32, i32};
|
|
LLVMStructSetBody(point_ty, point_fields, 2, 0);
|
|
|
|
// ==========================================
|
|
// Function: void point_init(Point* p, i32 x, i32 y)
|
|
// ==========================================
|
|
LLVMTypeRef init_params[] = {ptr, i32, i32};
|
|
LLVMTypeRef init_ty = LLVMFunctionType(void_ty, init_params, 3, 0);
|
|
LLVMValueRef init_func = LLVMAddFunction(mod, "point_init", init_ty);
|
|
|
|
LLVMValueRef p = LLVMGetParam(init_func, 0);
|
|
LLVMValueRef x = LLVMGetParam(init_func, 1);
|
|
LLVMValueRef y = LLVMGetParam(init_func, 2);
|
|
LLVMSetValueName2(p, "p", 1);
|
|
LLVMSetValueName2(x, "x", 1);
|
|
LLVMSetValueName2(y, "y", 1);
|
|
|
|
LLVMBasicBlockRef init_entry =
|
|
LLVMAppendBasicBlockInContext(ctx, init_func, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, init_entry);
|
|
|
|
// Store x to p->x (field 0)
|
|
LLVMValueRef x_ptr = LLVMBuildStructGEP2(builder, point_ty, p, 0, "x_ptr");
|
|
LLVMBuildStore(builder, x, x_ptr);
|
|
|
|
// Store y to p->y (field 1)
|
|
LLVMValueRef y_ptr = LLVMBuildStructGEP2(builder, point_ty, p, 1, "y_ptr");
|
|
LLVMBuildStore(builder, y, y_ptr);
|
|
|
|
LLVMBuildRetVoid(builder);
|
|
|
|
// ==========================================
|
|
// Function: void point_add(Point* a, Point* b, Point* result)
|
|
// ==========================================
|
|
LLVMTypeRef add_params[] = {ptr, ptr, ptr};
|
|
LLVMTypeRef add_ty = LLVMFunctionType(void_ty, add_params, 3, 0);
|
|
LLVMValueRef add_func = LLVMAddFunction(mod, "point_add", add_ty);
|
|
|
|
LLVMValueRef a = LLVMGetParam(add_func, 0);
|
|
LLVMValueRef b = LLVMGetParam(add_func, 1);
|
|
LLVMValueRef result = LLVMGetParam(add_func, 2);
|
|
LLVMSetValueName2(a, "a", 1);
|
|
LLVMSetValueName2(b, "b", 1);
|
|
LLVMSetValueName2(result, "result", 6);
|
|
|
|
LLVMBasicBlockRef add_entry =
|
|
LLVMAppendBasicBlockInContext(ctx, add_func, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, add_entry);
|
|
|
|
// Load a->x and a->y
|
|
LLVMValueRef a_x_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, a, 0, "a_x_ptr");
|
|
LLVMValueRef a_y_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, a, 1, "a_y_ptr");
|
|
LLVMValueRef a_x = LLVMBuildLoad2(builder, i32, a_x_ptr, "a_x");
|
|
LLVMValueRef a_y = LLVMBuildLoad2(builder, i32, a_y_ptr, "a_y");
|
|
|
|
// Load b->x and b->y
|
|
LLVMValueRef b_x_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, b, 0, "b_x_ptr");
|
|
LLVMValueRef b_y_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, b, 1, "b_y_ptr");
|
|
LLVMValueRef b_x = LLVMBuildLoad2(builder, i32, b_x_ptr, "b_x");
|
|
LLVMValueRef b_y = LLVMBuildLoad2(builder, i32, b_y_ptr, "b_y");
|
|
|
|
// Compute sum
|
|
LLVMValueRef sum_x = LLVMBuildAdd(builder, a_x, b_x, "sum_x");
|
|
LLVMValueRef sum_y = LLVMBuildAdd(builder, a_y, b_y, "sum_y");
|
|
|
|
// Store to result
|
|
LLVMValueRef result_x_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, result, 0, "result_x_ptr");
|
|
LLVMValueRef result_y_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, result, 1, "result_y_ptr");
|
|
LLVMBuildStore(builder, sum_x, result_x_ptr);
|
|
LLVMBuildStore(builder, sum_y, result_y_ptr);
|
|
|
|
LLVMBuildRetVoid(builder);
|
|
|
|
// ==========================================
|
|
// Function: i32 point_manhattan_distance(Point* p)
|
|
// Returns |x| + |y| (simplified: just x + y for demo)
|
|
// ==========================================
|
|
LLVMTypeRef dist_params[] = {ptr};
|
|
LLVMTypeRef dist_ty = LLVMFunctionType(i32, dist_params, 1, 0);
|
|
LLVMValueRef dist_func = LLVMAddFunction(mod, "point_manhattan", dist_ty);
|
|
|
|
LLVMValueRef dist_p = LLVMGetParam(dist_func, 0);
|
|
LLVMSetValueName2(dist_p, "p", 1);
|
|
|
|
LLVMBasicBlockRef dist_entry =
|
|
LLVMAppendBasicBlockInContext(ctx, dist_func, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, dist_entry);
|
|
|
|
LLVMValueRef px_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, dist_p, 0, "px_ptr");
|
|
LLVMValueRef py_ptr =
|
|
LLVMBuildStructGEP2(builder, point_ty, dist_p, 1, "py_ptr");
|
|
LLVMValueRef px = LLVMBuildLoad2(builder, i32, px_ptr, "px");
|
|
LLVMValueRef py = LLVMBuildLoad2(builder, i32, py_ptr, "py");
|
|
LLVMValueRef dist = LLVMBuildAdd(builder, px, py, "dist");
|
|
LLVMBuildRet(builder, dist);
|
|
|
|
// ==========================================
|
|
// Function: i32 test_points()
|
|
// Creates two points, adds them, returns manhattan distance
|
|
// ==========================================
|
|
LLVMTypeRef test_ty = LLVMFunctionType(i32, nullptr, 0, 0);
|
|
LLVMValueRef test_func = LLVMAddFunction(mod, "test_points", test_ty);
|
|
|
|
LLVMBasicBlockRef test_entry =
|
|
LLVMAppendBasicBlockInContext(ctx, test_func, "entry");
|
|
LLVMPositionBuilderAtEnd(builder, test_entry);
|
|
|
|
// Allocate three Points
|
|
LLVMValueRef p1 = LLVMBuildAlloca(builder, point_ty, "p1");
|
|
LLVMValueRef p2 = LLVMBuildAlloca(builder, point_ty, "p2");
|
|
LLVMValueRef p3 = LLVMBuildAlloca(builder, point_ty, "p3");
|
|
|
|
// Initialize p1 = (3, 4)
|
|
LLVMValueRef init_args1[] = {p1, LLVMConstInt(i32, 3, 0),
|
|
LLVMConstInt(i32, 4, 0)};
|
|
LLVMBuildCall2(builder, init_ty, init_func, init_args1, 3, "");
|
|
|
|
// Initialize p2 = (1, 2)
|
|
LLVMValueRef init_args2[] = {p2, LLVMConstInt(i32, 1, 0),
|
|
LLVMConstInt(i32, 2, 0)};
|
|
LLVMBuildCall2(builder, init_ty, init_func, init_args2, 3, "");
|
|
|
|
// Add p1 + p2 -> p3
|
|
LLVMValueRef add_args[] = {p1, p2, p3};
|
|
LLVMBuildCall2(builder, add_ty, add_func, add_args, 3, "");
|
|
|
|
// Get manhattan distance of p3
|
|
LLVMValueRef dist_args[] = {p3};
|
|
LLVMValueRef final_dist =
|
|
LLVMBuildCall2(builder, dist_ty, dist_func, dist_args, 1, "final_dist");
|
|
|
|
LLVMBuildRet(builder, final_dist);
|
|
|
|
// ==========================================
|
|
// Global constant Point
|
|
// ==========================================
|
|
LLVMValueRef origin_vals[] = {LLVMConstInt(i32, 0, 0),
|
|
LLVMConstInt(i32, 0, 0)};
|
|
LLVMValueRef origin_const = LLVMConstNamedStruct(point_ty, origin_vals, 2);
|
|
LLVMValueRef origin_global = LLVMAddGlobal(mod, point_ty, "origin");
|
|
LLVMSetInitializer(origin_global, origin_const);
|
|
LLVMSetGlobalConstant(origin_global, 1);
|
|
|
|
LLVMDisposeBuilder(builder);
|
|
|
|
// Verify module
|
|
char *error = nullptr;
|
|
if (LLVMVerifyModule(mod, LLVMReturnStatusAction, &error)) {
|
|
fprintf(stderr, "; Verification failed: %s\n", error);
|
|
LLVMDisposeMessage(error);
|
|
LLVMDisposeModule(mod);
|
|
LLVMContextDispose(ctx);
|
|
return 1;
|
|
}
|
|
LLVMDisposeMessage(error);
|
|
|
|
// Print diagnostic comments
|
|
printf("; Test: test_struct\n");
|
|
printf("; Integration test: Point struct manipulation\n");
|
|
printf(";\n");
|
|
printf("; Struct definition:\n");
|
|
printf("; %%Point = type { i32, i32 } ; x, y fields\n");
|
|
printf(";\n");
|
|
printf("; Functions:\n");
|
|
printf("; point_init(Point*, i32, i32) -> void\n");
|
|
printf("; point_add(Point*, Point*, Point*) -> void\n");
|
|
printf("; point_manhattan(Point*) -> i32\n");
|
|
printf("; test_points() -> i32\n");
|
|
printf(";\n");
|
|
printf("; test_points creates:\n");
|
|
printf("; p1 = (3, 4)\n");
|
|
printf("; p2 = (1, 2)\n");
|
|
printf("; p3 = p1 + p2 = (4, 6)\n");
|
|
printf("; returns manhattan(p3) = 4 + 6 = 10\n");
|
|
printf(";\n");
|
|
printf("; Struct type info:\n");
|
|
printf("; name: %s\n", LLVMGetStructName(point_ty));
|
|
printf("; num elements: %u\n", LLVMCountStructElementTypes(point_ty));
|
|
printf("; is packed: %s\n", LLVMIsPackedStruct(point_ty) ? "yes" : "no");
|
|
printf("; is opaque: %s\n", LLVMIsOpaqueStruct(point_ty) ? "yes" : "no");
|
|
printf("\n");
|
|
|
|
// Print module IR
|
|
char *ir = LLVMPrintModuleToString(mod);
|
|
printf("%s", ir);
|
|
LLVMDisposeMessage(ir);
|
|
|
|
// Cleanup
|
|
LLVMDisposeModule(mod);
|
|
LLVMContextDispose(ctx);
|
|
|
|
return 0;
|
|
}
|