extend default to s64
This commit is contained in:
345
src/codegen.zig
345
src/codegen.zig
@@ -58,6 +58,8 @@ pub const CodeGen = struct {
|
||||
namespaces: std.StringHashMap(void),
|
||||
// Functions declared with #builtin (only available when imported)
|
||||
builtin_functions: std.StringHashMap(void),
|
||||
// Function signatures: maps function name to display signature (e.g. "test :: () -> s32")
|
||||
fn_signatures: std.StringHashMap([]const u8),
|
||||
// Active namespace during body generation of imported modules
|
||||
current_namespace: ?[]const u8 = null,
|
||||
// Diagnostics list (optional, for structured error reporting)
|
||||
@@ -102,6 +104,7 @@ pub const CodeGen = struct {
|
||||
vector_cat,
|
||||
array_cat,
|
||||
slice_cat,
|
||||
pointer_cat,
|
||||
};
|
||||
|
||||
const AnyTypeEntry = struct {
|
||||
@@ -181,6 +184,7 @@ pub const CodeGen = struct {
|
||||
.generic_struct_templates = std.StringHashMap(GenericStructTemplate).init(allocator),
|
||||
.namespaces = std.StringHashMap(void).init(allocator),
|
||||
.builtin_functions = std.StringHashMap(void).init(allocator),
|
||||
.fn_signatures = std.StringHashMap([]const u8).init(allocator),
|
||||
.variadic_functions = std.StringHashMap(VariadicInfo).init(allocator),
|
||||
.fn_param_types = std.StringHashMap([]const Type).init(allocator),
|
||||
.any_type_id_map = std.StringHashMap(u64).init(allocator),
|
||||
@@ -201,6 +205,7 @@ pub const CodeGen = struct {
|
||||
self.generic_struct_templates.deinit();
|
||||
self.namespaces.deinit();
|
||||
self.builtin_functions.deinit();
|
||||
self.fn_signatures.deinit();
|
||||
self.variadic_functions.deinit();
|
||||
self.any_type_id_map.deinit();
|
||||
self.any_type_entries.deinit();
|
||||
@@ -229,7 +234,7 @@ pub const CodeGen = struct {
|
||||
.void_type => c.LLVMVoidTypeInContext(self.context),
|
||||
.boolean => c.LLVMInt1TypeInContext(self.context),
|
||||
.string_type, .slice_type => self.getStringStructType(), // slices use same {ptr, i32} layout
|
||||
.enum_type => c.LLVMInt32TypeInContext(self.context),
|
||||
.enum_type => c.LLVMInt64TypeInContext(self.context),
|
||||
.struct_type => |name| if (self.struct_types.get(name)) |info| info.llvm_type else unreachable,
|
||||
.union_type => |name| if (self.union_types.get(name)) |info| info.llvm_type else unreachable,
|
||||
.array_type => |info| {
|
||||
@@ -249,7 +254,7 @@ pub const CodeGen = struct {
|
||||
fn getAnyStructType(self: *CodeGen) c.LLVMTypeRef {
|
||||
if (self.any_struct_type) |t| return t;
|
||||
var field_types = [_]c.LLVMTypeRef{
|
||||
c.LLVMInt32TypeInContext(self.context), // type tag
|
||||
c.LLVMInt64TypeInContext(self.context), // type tag
|
||||
c.LLVMInt64TypeInContext(self.context), // value (fits all primitives)
|
||||
};
|
||||
self.any_struct_type = c.LLVMStructTypeInContext(self.context, &field_types, 2, 0);
|
||||
@@ -285,6 +290,7 @@ pub const CodeGen = struct {
|
||||
.vector_type => .vector_cat,
|
||||
.array_type => .array_cat,
|
||||
.slice_type => .slice_cat,
|
||||
.pointer_type, .many_pointer_type => .pointer_cat,
|
||||
else => .struct_cat, // fallback
|
||||
};
|
||||
try self.any_type_entries.put(name, .{
|
||||
@@ -320,6 +326,8 @@ pub const CodeGen = struct {
|
||||
.vector_type => |info| _ = try self.getAnyTypeId(try std.fmt.allocPrint(self.allocator, "vec[{d}]{s}", .{ info.length, info.element_name }), sx_type),
|
||||
.array_type => |info| _ = try self.getAnyTypeId(try std.fmt.allocPrint(self.allocator, "[{d}]{s}", .{ info.length, info.element_name }), sx_type),
|
||||
.slice_type => |info| _ = try self.getAnyTypeId(try std.fmt.allocPrint(self.allocator, "[]{s}", .{info.element_name}), sx_type),
|
||||
.pointer_type => |info| _ = try self.getAnyTypeId(try std.fmt.allocPrint(self.allocator, "*{s}", .{info.pointee_name}), sx_type),
|
||||
.many_pointer_type => |info| _ = try self.getAnyTypeId(try std.fmt.allocPrint(self.allocator, "[*]{s}", .{info.element_name}), sx_type),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@@ -329,7 +337,6 @@ pub const CodeGen = struct {
|
||||
/// Complex values (strings, structs, unions) are stored via pointer (alloca + ptr-to-int).
|
||||
fn buildAnyValue(self: *CodeGen, val: c.LLVMValueRef, ty: Type) !c.LLVMValueRef {
|
||||
const any_ty = self.getAnyStructType();
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const undef = c.LLVMGetUndef(any_ty);
|
||||
|
||||
@@ -353,7 +360,7 @@ pub const CodeGen = struct {
|
||||
.meta_type => ANY_TAG_TYPE,
|
||||
else => ANY_TAG_S32,
|
||||
};
|
||||
const tag_val = c.LLVMConstInt(i32_ty, tag, 0);
|
||||
const tag_val = c.LLVMConstInt(i64_ty, tag, 0);
|
||||
const with_tag = c.LLVMBuildInsertValue(self.builder, undef, tag_val, 0, "any_tag");
|
||||
|
||||
// Convert value to i64
|
||||
@@ -413,9 +420,12 @@ pub const CodeGen = struct {
|
||||
break :blk c.LLVMBuildPtrToInt(self.builder, alloca, i64_ty, "any_slice");
|
||||
},
|
||||
.pointer_type, .many_pointer_type => c.LLVMBuildPtrToInt(self.builder, val, i64_ty, "any_ptr"),
|
||||
.meta_type => blk: {
|
||||
// Meta type is a pointer (global string) — convert via ptrtoint
|
||||
break :blk c.LLVMBuildPtrToInt(self.builder, val, i64_ty, "any_type");
|
||||
.meta_type => |mt| blk: {
|
||||
// Meta type: wrap raw char ptr in string slice {ptr, len} for extraction
|
||||
const str_slice = self.buildStringSlice(val, mt.name.len);
|
||||
const alloca = c.LLVMBuildAlloca(self.builder, self.getStringStructType(), "any_type_tmp");
|
||||
_ = c.LLVMBuildStore(self.builder, str_slice, alloca);
|
||||
break :blk c.LLVMBuildPtrToInt(self.builder, alloca, i64_ty, "any_type");
|
||||
},
|
||||
else => c.LLVMBuildSExt(self.builder, val, i64_ty, "any_val"),
|
||||
};
|
||||
@@ -426,18 +436,18 @@ pub const CodeGen = struct {
|
||||
if (self.string_struct_type) |t| return t;
|
||||
var field_types = [_]c.LLVMTypeRef{
|
||||
c.LLVMPointerTypeInContext(self.context, 0), // ptr
|
||||
c.LLVMInt32TypeInContext(self.context), // len
|
||||
c.LLVMInt64TypeInContext(self.context), // len
|
||||
};
|
||||
self.string_struct_type = c.LLVMStructTypeInContext(self.context, &field_types, 2, 0);
|
||||
return self.string_struct_type.?;
|
||||
}
|
||||
|
||||
/// Build a string slice {ptr, len} from a raw pointer and a constant length.
|
||||
fn buildStringSlice(self: *CodeGen, ptr: c.LLVMValueRef, len: u32) c.LLVMValueRef {
|
||||
fn buildStringSlice(self: *CodeGen, ptr: c.LLVMValueRef, len: u64) c.LLVMValueRef {
|
||||
const str_ty = self.getStringStructType();
|
||||
const undef = c.LLVMGetUndef(str_ty);
|
||||
const with_ptr = c.LLVMBuildInsertValue(self.builder, undef, ptr, 0, "str_ptr");
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), len, 0);
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), len, 0);
|
||||
return c.LLVMBuildInsertValue(self.builder, with_ptr, len_val, 1, "str_slice");
|
||||
}
|
||||
|
||||
@@ -525,6 +535,7 @@ pub const CodeGen = struct {
|
||||
} else {
|
||||
try self.registerFnDecl(fd);
|
||||
}
|
||||
try self.fn_signatures.put(fd.name, self.buildFnSignature(fd));
|
||||
},
|
||||
.enum_decl => |ed| {
|
||||
try self.enum_types.put(ed.name, ed.variants);
|
||||
@@ -560,6 +571,14 @@ pub const CodeGen = struct {
|
||||
} else if (result_ty.isUnion()) {
|
||||
try self.type_aliases.put(cd.name, result_ty.union_type);
|
||||
}
|
||||
} else if (self.builtin_functions.contains(cn)) {
|
||||
// Builtin type function (e.g., Vector(4, f32), Array(5, s32))
|
||||
if (self.resolveBuiltinType(cn, cd.value.data.call.args)) |result_ty| {
|
||||
const display = try result_ty.displayName(self.allocator);
|
||||
try self.type_aliases.put(cd.name, display);
|
||||
} else {
|
||||
try self.registerTopLevelConstant(cd);
|
||||
}
|
||||
} else {
|
||||
try self.registerTopLevelConstant(cd);
|
||||
}
|
||||
@@ -727,6 +746,8 @@ pub const CodeGen = struct {
|
||||
break :blk self.buildStringSlice(ptr, @intCast(v.len));
|
||||
},
|
||||
.void_val => c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0),
|
||||
.pointer_val => c.LLVMConstNull(c.LLVMPointerTypeInContext(self.context, 0)),
|
||||
.null_val => c.LLVMConstNull(c.LLVMPointerTypeInContext(self.context, 0)),
|
||||
.struct_val, .array_val, .type_val, .function_val => unreachable,
|
||||
};
|
||||
}
|
||||
@@ -1084,10 +1105,10 @@ pub const CodeGen = struct {
|
||||
|
||||
const name_z = try self.allocator.dupeZ(u8, mangled_name);
|
||||
const union_ty = c.LLVMStructCreateNamed(self.context, name_z.ptr);
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const i8_ty = c.LLVMInt8TypeInContext(self.context);
|
||||
const payload_array_ty = c.LLVMArrayType2(i8_ty, max_payload_size);
|
||||
var fields = [2]c.LLVMTypeRef{ i32_ty, payload_array_ty };
|
||||
var fields = [2]c.LLVMTypeRef{ i64_ty, payload_array_ty };
|
||||
c.LLVMStructSetBody(union_ty, &fields, 2, 0);
|
||||
|
||||
try self.union_types.put(mangled_name, .{
|
||||
@@ -1273,8 +1294,8 @@ pub const CodeGen = struct {
|
||||
// For function calls, look up the registered function's return type
|
||||
if (expr.data == .call) {
|
||||
if (self.resolveCalleeName(expr.data.call)) |callee_name| {
|
||||
const callee_name_z = self.allocator.dupeZ(u8, callee_name) catch return Type.s(32);
|
||||
const callee_fn = c.LLVMGetNamedFunction(self.module, callee_name_z.ptr) orelse return Type.s(32);
|
||||
const callee_name_z = self.allocator.dupeZ(u8, callee_name) catch return Type.s(64);
|
||||
const callee_fn = c.LLVMGetNamedFunction(self.module, callee_name_z.ptr) orelse return Type.s(64);
|
||||
const fn_type = c.LLVMGlobalGetValueType(callee_fn);
|
||||
const ret_llvm = c.LLVMGetReturnType(fn_type);
|
||||
return self.llvmTypeToSxType(ret_llvm);
|
||||
@@ -1315,7 +1336,7 @@ pub const CodeGen = struct {
|
||||
const elem_llvm = c.LLVMGetElementType(llvm_ty);
|
||||
const length: u32 = @intCast(c.LLVMGetArrayLength2(llvm_ty));
|
||||
const elem_ty = self.llvmTypeToSxType(elem_llvm);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(32);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(64);
|
||||
return .{ .array_type = .{ .element_name = elem_name, .length = length } };
|
||||
}
|
||||
// Check for vector types
|
||||
@@ -1323,10 +1344,10 @@ pub const CodeGen = struct {
|
||||
const elem_llvm = c.LLVMGetElementType(llvm_ty);
|
||||
const length = c.LLVMGetVectorSize(llvm_ty);
|
||||
const elem_ty = self.llvmTypeToSxType(elem_llvm);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(32);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(64);
|
||||
return .{ .vector_type = .{ .element_name = elem_name, .length = length } };
|
||||
}
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
}
|
||||
|
||||
fn registerComptimeGlobal(self: *CodeGen, name: []const u8, expr: *Node, type_override: ?Type) !void {
|
||||
@@ -1673,7 +1694,7 @@ pub const CodeGen = struct {
|
||||
if (vd.value) |val| {
|
||||
const meta_name = self.asTypeName(val);
|
||||
if (meta_name) |raw_name| {
|
||||
const type_name = self.resolveDisplayName(raw_name);
|
||||
const type_name = try self.allocator.dupeZ(u8, raw_name);
|
||||
const name_z = try self.allocator.dupeZ(u8, vd.name);
|
||||
const ptr_ty = c.LLVMPointerTypeInContext(self.context, 0);
|
||||
const alloca = c.LLVMBuildAlloca(self.builder, ptr_ty, name_z.ptr);
|
||||
@@ -1685,7 +1706,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
var sx_ty: Type = Type.s(32);
|
||||
var sx_ty: Type = Type.s(64);
|
||||
|
||||
if (vd.type_annotation) |ta| {
|
||||
sx_ty = self.resolveType(ta);
|
||||
@@ -1928,7 +1949,7 @@ pub const CodeGen = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
var sx_ty: Type = Type.s(32);
|
||||
var sx_ty: Type = Type.s(64);
|
||||
|
||||
if (cd.type_annotation) |ta| {
|
||||
sx_ty = self.resolveType(ta);
|
||||
@@ -1989,14 +2010,22 @@ pub const CodeGen = struct {
|
||||
return self.emitErrorFmt("undefined variable '{s}'", .{name});
|
||||
};
|
||||
|
||||
// Meta type reassignment: x = Vec4 or x = f64
|
||||
// Meta type reassignment: x = Vec4, x = f64, x = test
|
||||
if (entry.ty == .meta_type and asgn.op == .assign) {
|
||||
if (self.asTypeName(asgn.value)) |raw_name| {
|
||||
const type_name = self.resolveDisplayName(raw_name);
|
||||
const raw_name = self.asTypeName(asgn.value) orelse blk: {
|
||||
// Also accept function names as meta_type values (use signature)
|
||||
if (asgn.value.data == .identifier) {
|
||||
const fn_name = asgn.value.data.identifier.name;
|
||||
if (self.fn_signatures.get(fn_name)) |sig| break :blk sig;
|
||||
}
|
||||
break :blk @as(?[]const u8, null);
|
||||
};
|
||||
if (raw_name) |rn| {
|
||||
const type_name = try self.allocator.dupeZ(u8, rn);
|
||||
const str_val = c.LLVMBuildGlobalStringPtr(self.builder, type_name.ptr, "type_name");
|
||||
_ = c.LLVMBuildStore(self.builder, str_val, entry.ptr);
|
||||
if (self.named_values.getPtr(name)) |entry_ptr| {
|
||||
entry_ptr.ty = .{ .meta_type = .{ .name = raw_name } };
|
||||
entry_ptr.ty = .{ .meta_type = .{ .name = rn } };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -2258,8 +2287,8 @@ pub const CodeGen = struct {
|
||||
self.current_span = node.span;
|
||||
switch (node.data) {
|
||||
.int_literal => |lit| {
|
||||
const i32_type = c.LLVMInt32TypeInContext(self.context);
|
||||
return c.LLVMConstInt(i32_type, @bitCast(@as(i64, lit.value)), 0);
|
||||
const i64_type = c.LLVMInt64TypeInContext(self.context);
|
||||
return c.LLVMConstInt(i64_type, @bitCast(@as(i64, lit.value)), 0);
|
||||
},
|
||||
.float_literal => |lit| {
|
||||
const f32_type = c.LLVMFloatTypeInContext(self.context);
|
||||
@@ -2617,13 +2646,13 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Union LLVM type: { i32, [max_payload_size x i8] }
|
||||
// Union LLVM type: { i64, [max_payload_size x i8] }
|
||||
const name_z = try self.allocator.dupeZ(u8, ud.name);
|
||||
const union_ty = c.LLVMStructCreateNamed(self.context, name_z.ptr);
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const i8_ty = c.LLVMInt8TypeInContext(self.context);
|
||||
const payload_array_ty = c.LLVMArrayType2(i8_ty, max_payload_size);
|
||||
var fields = [2]c.LLVMTypeRef{ i32_ty, payload_array_ty };
|
||||
var fields = [2]c.LLVMTypeRef{ i64_ty, payload_array_ty };
|
||||
c.LLVMStructSetBody(union_ty, &fields, 2, 0);
|
||||
|
||||
try self.union_types.put(ud.name, .{
|
||||
@@ -2654,11 +2683,11 @@ pub const CodeGen = struct {
|
||||
|
||||
// Alloca union
|
||||
const alloca = c.LLVMBuildAlloca(self.builder, info.llvm_type, "union_tmp");
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
|
||||
// Store tag (field 0)
|
||||
const tag_gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, alloca, 0, "tag");
|
||||
_ = c.LLVMBuildStore(self.builder, c.LLVMConstInt(i32_ty, idx, 0), tag_gep);
|
||||
_ = c.LLVMBuildStore(self.builder, c.LLVMConstInt(i64_ty, idx, 0), tag_gep);
|
||||
|
||||
// Store payload (field 1) if not void
|
||||
if (ul.payload) |payload_node| {
|
||||
@@ -2790,14 +2819,14 @@ pub const CodeGen = struct {
|
||||
}
|
||||
|
||||
// Build slice {ptr, len}
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i32_ty, 0, 0);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i64_ty, 0, 0);
|
||||
var gep_indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const elem_ptr = c.LLVMBuildGEP2(self.builder, llvm_arr_ty, arr_alloca, &gep_indices, 2, "slice_data");
|
||||
const slice_llvm_ty = self.getStringStructType();
|
||||
var slice_val = c.LLVMGetUndef(slice_llvm_ty);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, elem_ptr, 0, "slice_ptr");
|
||||
const len_val = c.LLVMConstInt(i32_ty, n, 0);
|
||||
const len_val = c.LLVMConstInt(i64_ty, n, 0);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, len_val, 1, "slice_len");
|
||||
return slice_val;
|
||||
}
|
||||
@@ -2942,15 +2971,15 @@ pub const CodeGen = struct {
|
||||
break :blk try self.genExpr(node);
|
||||
};
|
||||
// GEP to get pointer to first element
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i32_ty, 0, 0);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i64_ty, 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const elem_ptr = c.LLVMBuildGEP2(self.builder, self.typeToLLVM(src_ty), arr_alloca, &indices, 2, "arr_data");
|
||||
// Build slice struct {ptr, len}
|
||||
const slice_ty = self.getStringStructType();
|
||||
var slice_val = c.LLVMGetUndef(slice_ty);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, elem_ptr, 0, "slice_ptr");
|
||||
const len_val = c.LLVMConstInt(i32_ty, arr_info.length, 0);
|
||||
const len_val = c.LLVMConstInt(i64_ty, arr_info.length, 0);
|
||||
slice_val = c.LLVMBuildInsertValue(self.builder, slice_val, len_val, 1, "slice_len");
|
||||
return slice_val;
|
||||
}
|
||||
@@ -3022,7 +3051,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
if (target_ty.isEnum()) {
|
||||
return c.LLVMBuildTrunc(self.builder, i64_val, c.LLVMInt32TypeInContext(self.context), "any_to_enum");
|
||||
return i64_val;
|
||||
}
|
||||
if (target_ty.isUnion()) {
|
||||
const uname = target_ty.union_type;
|
||||
@@ -3031,6 +3060,9 @@ pub const CodeGen = struct {
|
||||
return c.LLVMBuildLoad2(self.builder, info.llvm_type, ptr, "any_to_union");
|
||||
}
|
||||
}
|
||||
if (target_ty.isPointer() or target_ty.isManyPointer()) {
|
||||
return c.LLVMBuildIntToPtr(self.builder, i64_val, c.LLVMPointerTypeInContext(self.context, 0), "any_to_ptr");
|
||||
}
|
||||
return i64_val;
|
||||
}
|
||||
|
||||
@@ -3061,6 +3093,15 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer → int: PtrToInt
|
||||
if ((src_ty.isPointer() or src_ty.isManyPointer()) and target_ty.isInt()) {
|
||||
const as_i64 = c.LLVMBuildPtrToInt(self.builder, val, c.LLVMInt64TypeInContext(self.context), "ptrtoint");
|
||||
if (target_ty.bitWidth() < 64) {
|
||||
return c.LLVMBuildTrunc(self.builder, as_i64, target_llvm, "ptr_trunc");
|
||||
}
|
||||
return as_i64;
|
||||
}
|
||||
|
||||
// Union → int: extract the tag field (index 0)
|
||||
if (src_ty.isUnion() and target_ty.isInt()) {
|
||||
const uname = src_ty.union_type;
|
||||
@@ -3149,19 +3190,19 @@ pub const CodeGen = struct {
|
||||
if (call_node.args.len != 1) return self.emitError("size_of expects exactly 1 argument");
|
||||
const ty = self.resolveType(call_node.args[0]);
|
||||
if (std.meta.eql(ty, Type.void_type)) {
|
||||
return c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
return c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), 0, 0);
|
||||
}
|
||||
const llvm_ty = self.typeToLLVM(ty);
|
||||
const data_layout = c.LLVMGetModuleDataLayout(self.module);
|
||||
const size = c.LLVMStoreSizeOfType(data_layout, llvm_ty);
|
||||
return c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), size, 0);
|
||||
return c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), size, 0);
|
||||
}
|
||||
|
||||
fn genTypeOf(self: *CodeGen, call_node: ast.Call) !c.LLVMValueRef {
|
||||
if (call_node.args.len != 1) return self.emitError("type_of expects exactly 1 argument");
|
||||
const arg = call_node.args[0];
|
||||
const arg_ty = self.inferType(arg);
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
|
||||
// For Any values: extract the runtime tag (field 0)
|
||||
if (arg_ty.isAny()) {
|
||||
@@ -3184,7 +3225,7 @@ pub const CodeGen = struct {
|
||||
.meta_type => ANY_TAG_TYPE,
|
||||
else => ANY_TAG_S32,
|
||||
};
|
||||
return c.LLVMConstInt(i32_ty, tag, 0);
|
||||
return c.LLVMConstInt(i64_ty, tag, 0);
|
||||
}
|
||||
|
||||
fn genTypeName(self: *CodeGen, call_node: ast.Call) !c.LLVMValueRef {
|
||||
@@ -3197,27 +3238,27 @@ pub const CodeGen = struct {
|
||||
fn genFieldCount(self: *CodeGen, call_node: ast.Call) !c.LLVMValueRef {
|
||||
if (call_node.args.len != 1) return self.emitError("field_count expects exactly 1 argument");
|
||||
const ty = self.resolveType(call_node.args[0]);
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
if (ty.isStruct()) {
|
||||
const info = self.struct_types.get(ty.struct_type) orelse
|
||||
return self.emitErrorFmt("unknown struct type '{s}'", .{ty.struct_type});
|
||||
return c.LLVMConstInt(i32_ty, info.field_names.len, 0);
|
||||
return c.LLVMConstInt(i64_ty, info.field_names.len, 0);
|
||||
}
|
||||
if (ty.isEnum()) {
|
||||
const variants = self.enum_types.get(ty.enum_type) orelse
|
||||
return self.emitErrorFmt("unknown enum type '{s}'", .{ty.enum_type});
|
||||
return c.LLVMConstInt(i32_ty, variants.len, 0);
|
||||
return c.LLVMConstInt(i64_ty, variants.len, 0);
|
||||
}
|
||||
if (ty.isVector()) {
|
||||
return c.LLVMConstInt(i32_ty, ty.vector_type.length, 0);
|
||||
return c.LLVMConstInt(i64_ty, ty.vector_type.length, 0);
|
||||
}
|
||||
if (ty.isUnion()) {
|
||||
const info = self.union_types.get(ty.union_type) orelse
|
||||
return self.emitErrorFmt("unknown union type '{s}'", .{ty.union_type});
|
||||
return c.LLVMConstInt(i32_ty, info.variant_names.len, 0);
|
||||
return c.LLVMConstInt(i64_ty, info.variant_names.len, 0);
|
||||
}
|
||||
if (ty.isArray()) {
|
||||
return c.LLVMConstInt(i32_ty, ty.array_type.length, 0);
|
||||
return c.LLVMConstInt(i64_ty, ty.array_type.length, 0);
|
||||
}
|
||||
return self.emitError("field_count requires a struct, enum, vector, union, or array type");
|
||||
}
|
||||
@@ -3294,7 +3335,7 @@ pub const CodeGen = struct {
|
||||
|
||||
// Read tag (field 0)
|
||||
const tag_ptr = c.LLVMBuildStructGEP2(self.builder, uinfo.llvm_type, union_alloca, 0, "fv_tag_ptr");
|
||||
const tag_val = c.LLVMBuildLoad2(self.builder, c.LLVMInt32TypeInContext(self.context), tag_ptr, "fv_tag");
|
||||
const tag_val = c.LLVMBuildLoad2(self.builder, c.LLVMInt64TypeInContext(self.context), tag_ptr, "fv_tag");
|
||||
const payload_ptr = c.LLVMBuildStructGEP2(self.builder, uinfo.llvm_type, union_alloca, 1, "fv_payload_ptr");
|
||||
|
||||
const n = uinfo.variant_names.len;
|
||||
@@ -3309,13 +3350,13 @@ pub const CodeGen = struct {
|
||||
|
||||
for (uinfo.variant_types, 0..) |vty, vi| {
|
||||
const case_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "fv_ucase");
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), @intCast(vi), 0), case_bb);
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), @intCast(vi), 0), case_bb);
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, case_bb);
|
||||
|
||||
const any_val = if (vty == .void_type) blk: {
|
||||
// Void variant: return Any with void tag
|
||||
const undef = c.LLVMGetUndef(any_ty);
|
||||
const void_tag = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), ANY_TAG_VOID, 0);
|
||||
const void_tag = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), ANY_TAG_VOID, 0);
|
||||
const with_tag = c.LLVMBuildInsertValue(self.builder, undef, void_tag, 0, "void_tag");
|
||||
const zero_val = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), 0, 0);
|
||||
break :blk c.LLVMBuildInsertValue(self.builder, with_tag, zero_val, 1, "void_any");
|
||||
@@ -3403,7 +3444,7 @@ pub const CodeGen = struct {
|
||||
|
||||
for (0..n) |i| {
|
||||
const case_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "fv_case");
|
||||
const case_val = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), i, 0);
|
||||
const case_val = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), i, 0);
|
||||
c.LLVMAddCase(sw, case_val, case_bb);
|
||||
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, case_bb);
|
||||
@@ -3444,11 +3485,9 @@ pub const CodeGen = struct {
|
||||
const builtins = self.builtins orelse return self.emitError("builtins not available (missing #builtin import)");
|
||||
const size_val = try self.genExpr(args[0]);
|
||||
const i64_type = c.LLVMInt64TypeInContext(self.context);
|
||||
// Extend size to i64 for calloc
|
||||
const size_i64 = c.LLVMBuildSExt(self.builder, size_val, i64_type, "size64");
|
||||
// calloc(size + 1, 1) — extra byte for null terminator
|
||||
const one_i64 = c.LLVMConstInt(i64_type, 1, 0);
|
||||
const size_plus_one = c.LLVMBuildAdd(self.builder, size_i64, one_i64, "szp1");
|
||||
const size_plus_one = c.LLVMBuildAdd(self.builder, size_val, one_i64, "szp1");
|
||||
const calloc_fn = builtins.calloc_fn;
|
||||
const calloc_ty = c.LLVMGlobalGetValueType(calloc_fn);
|
||||
var calloc_args = [_]c.LLVMValueRef{ size_plus_one, one_i64 };
|
||||
@@ -3549,7 +3588,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
if (entry.ty.isArray()) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) {
|
||||
return c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), entry.ty.array_type.length, 0);
|
||||
return c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), entry.ty.array_type.length, 0);
|
||||
}
|
||||
return self.emitErrorFmt("no field '{s}' on array (available: .len)", .{fa.field});
|
||||
}
|
||||
@@ -3623,15 +3662,14 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
if (obj_ty == .string_type) {
|
||||
// String indexing: extract ptr from slice, GEP + load i8 + zext to i32
|
||||
// String indexing: extract ptr from slice, GEP + load u8
|
||||
const str_val = try self.genExpr(ie.object);
|
||||
const ptr = c.LLVMBuildExtractValue(self.builder, str_val, 0, "str_ptr");
|
||||
const idx = try self.genExpr(ie.index);
|
||||
const i8_type = c.LLVMInt8TypeInContext(self.context);
|
||||
var gep_indices = [_]c.LLVMValueRef{idx};
|
||||
const gep = c.LLVMBuildGEP2(self.builder, i8_type, ptr, &gep_indices, 1, "stridx");
|
||||
const byte = c.LLVMBuildLoad2(self.builder, i8_type, gep, "byte");
|
||||
return c.LLVMBuildZExt(self.builder, byte, c.LLVMInt32TypeInContext(self.context), "char");
|
||||
return c.LLVMBuildLoad2(self.builder, i8_type, gep, "byte");
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
// Slice indexing: extract ptr, GEP with element type, load
|
||||
@@ -3672,8 +3710,8 @@ pub const CodeGen = struct {
|
||||
|
||||
fn genSliceExpr(self: *CodeGen, se: ast.SliceExpr) !c.LLVMValueRef {
|
||||
const obj_ty = self.inferType(se.object);
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i32_ty, 0, 0);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const zero = c.LLVMConstInt(i64_ty, 0, 0);
|
||||
const slice_struct_ty = self.getStringStructType();
|
||||
|
||||
// Resolve start (default: 0)
|
||||
@@ -3682,7 +3720,7 @@ pub const CodeGen = struct {
|
||||
if (obj_ty.isArray()) {
|
||||
const arr_info = obj_ty.array_type;
|
||||
// Resolve end (default: array length)
|
||||
const end_val = if (se.end) |e| try self.genExpr(e) else c.LLVMConstInt(i32_ty, arr_info.length, 0);
|
||||
const end_val = if (se.end) |e| try self.genExpr(e) else c.LLVMConstInt(i64_ty, arr_info.length, 0);
|
||||
// Get array alloca
|
||||
const arr_ptr = blk: {
|
||||
if (se.object.data == .identifier) {
|
||||
@@ -4042,7 +4080,7 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
// Pack variadic args into a slice {ptr, len}
|
||||
const elem_ty = Type.fromName(vi.element_type_name) orelse Type.s(32);
|
||||
const elem_ty = Type.fromName(vi.element_type_name) orelse Type.s(64);
|
||||
const elem_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
const var_arg_count = if (call_node.args.len > fixed_count) call_node.args.len - fixed_count else 0;
|
||||
|
||||
@@ -4056,10 +4094,10 @@ pub const CodeGen = struct {
|
||||
if (spread_operand.data == .identifier) {
|
||||
if (self.named_values.get(spread_operand.data.identifier.name)) |entry| {
|
||||
const arr_llvm_ty = self.typeToLLVM(spread_ty);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), 0, 0);
|
||||
var ptr_indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const arr_ptr = c.LLVMBuildGEP2(self.builder, arr_llvm_ty, entry.ptr, &ptr_indices, 2, "spread_ptr");
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), arr_info.length, 0);
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), arr_info.length, 0);
|
||||
const slice_val = self.buildStringSliceRT(arr_ptr, len_val);
|
||||
try arg_vals.append(self.allocator, slice_val);
|
||||
} else {
|
||||
@@ -4094,16 +4132,16 @@ pub const CodeGen = struct {
|
||||
_ = c.LLVMBuildStore(self.builder, arg_val, gep);
|
||||
}
|
||||
// Build slice: {ptr, len}
|
||||
const zero = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
const zero = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), 0, 0);
|
||||
var ptr_indices = [_]c.LLVMValueRef{ zero, zero };
|
||||
const arr_ptr = c.LLVMBuildGEP2(self.builder, arr_ty, arr_alloca, &ptr_indices, 2, "varargs_ptr");
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), @intCast(var_arg_count), 0);
|
||||
const len_val = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), @intCast(var_arg_count), 0);
|
||||
const slice_val = self.buildStringSliceRT(arr_ptr, len_val);
|
||||
try arg_vals.append(self.allocator, slice_val);
|
||||
} else {
|
||||
// Zero variadic args: pass empty slice {null, 0}
|
||||
const null_ptr = c.LLVMConstNull(c.LLVMPointerTypeInContext(self.context, 0));
|
||||
const zero_len = c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), 0, 0);
|
||||
const zero_len = c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), 0, 0);
|
||||
const slice_val = self.buildStringSliceRT(null_ptr, zero_len);
|
||||
try arg_vals.append(self.allocator, slice_val);
|
||||
}
|
||||
@@ -4466,7 +4504,7 @@ pub const CodeGen = struct {
|
||||
|
||||
// Create case BB
|
||||
const case_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "dispatch_case");
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(c.LLVMInt32TypeInContext(self.context), tag, 0), case_bb);
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(c.LLVMInt64TypeInContext(self.context), tag, 0), case_bb);
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, case_bb);
|
||||
|
||||
// Convert Any payload to the concrete type
|
||||
@@ -4594,7 +4632,7 @@ pub const CodeGen = struct {
|
||||
const ptr = c.LLVMBuildIntToPtr(self.builder, any_i64, c.LLVMPointerTypeInContext(self.context, 0), "any_to_struct_ptr");
|
||||
break :blk c.LLVMBuildLoad2(self.builder, info.llvm_type, ptr, "any_to_struct");
|
||||
},
|
||||
.enum_type => c.LLVMBuildTrunc(self.builder, any_i64, c.LLVMInt32TypeInContext(self.context), "any_to_enum"),
|
||||
.enum_type => any_i64,
|
||||
.union_type => |uname| blk: {
|
||||
const info = self.union_types.get(uname) orelse return self.emitErrorFmt("unknown union '{s}'", .{uname});
|
||||
const ptr = c.LLVMBuildIntToPtr(self.builder, any_i64, c.LLVMPointerTypeInContext(self.context, 0), "any_to_union_ptr");
|
||||
@@ -4609,7 +4647,8 @@ pub const CodeGen = struct {
|
||||
const ptr = c.LLVMBuildIntToPtr(self.builder, any_i64, c.LLVMPointerTypeInContext(self.context, 0), "any_to_slice_ptr");
|
||||
break :blk c.LLVMBuildLoad2(self.builder, self.getStringStructType(), ptr, "any_to_slice");
|
||||
},
|
||||
else => c.LLVMBuildTrunc(self.builder, any_i64, c.LLVMInt32TypeInContext(self.context), "any_to_default"),
|
||||
.pointer_type, .many_pointer_type => c.LLVMBuildIntToPtr(self.builder, any_i64, c.LLVMPointerTypeInContext(self.context, 0), "any_to_ptr"),
|
||||
else => any_i64,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4869,19 +4908,19 @@ pub const CodeGen = struct {
|
||||
|
||||
fn genForExpr(self: *CodeGen, for_expr: ast.ForExpr) !c.LLVMValueRef {
|
||||
const function = self.current_function;
|
||||
const i32_type = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_type = c.LLVMInt64TypeInContext(self.context);
|
||||
|
||||
// Determine iterable type and get length + element access info
|
||||
const iter_ty = self.inferType(for_expr.iterable);
|
||||
var len_val: c.LLVMValueRef = undefined;
|
||||
var elem_ty: Type = Type.s(32);
|
||||
var elem_ty: Type = Type.s(64);
|
||||
var iter_ptr: c.LLVMValueRef = undefined; // pointer to data
|
||||
var is_slice = false;
|
||||
|
||||
if (iter_ty.isSlice()) {
|
||||
is_slice = true;
|
||||
const info = iter_ty.slice_type;
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(32);
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(64);
|
||||
// Load slice value from alloca
|
||||
if (for_expr.iterable.data == .identifier) {
|
||||
if (self.named_values.get(for_expr.iterable.data.identifier.name)) |entry| {
|
||||
@@ -4892,8 +4931,8 @@ pub const CodeGen = struct {
|
||||
} else return self.emitError("for: slice iterable must be a variable");
|
||||
} else if (iter_ty.isArray()) {
|
||||
const info = iter_ty.array_type;
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(32);
|
||||
len_val = c.LLVMConstInt(i32_type, info.length, 0);
|
||||
elem_ty = Type.fromName(info.element_name) orelse Type.s(64);
|
||||
len_val = c.LLVMConstInt(i64_type, info.length, 0);
|
||||
// Get pointer to array
|
||||
if (for_expr.iterable.data == .identifier) {
|
||||
if (self.named_values.get(for_expr.iterable.data.identifier.name)) |entry| {
|
||||
@@ -4906,15 +4945,15 @@ pub const CodeGen = struct {
|
||||
|
||||
const elem_llvm_ty = self.typeToLLVM(elem_ty);
|
||||
|
||||
// Allocate it_index (s32) and it (element type)
|
||||
const idx_alloca = c.LLVMBuildAlloca(self.builder, i32_type, "it_index");
|
||||
_ = c.LLVMBuildStore(self.builder, c.LLVMConstInt(i32_type, 0, 0), idx_alloca);
|
||||
// Allocate it_index (s64) and it (element type)
|
||||
const idx_alloca = c.LLVMBuildAlloca(self.builder, i64_type, "it_index");
|
||||
_ = c.LLVMBuildStore(self.builder, c.LLVMConstInt(i64_type, 0, 0), idx_alloca);
|
||||
const it_alloca = c.LLVMBuildAlloca(self.builder, elem_llvm_ty, "it");
|
||||
|
||||
// Push scope and bind it, it_index
|
||||
try self.pushScope();
|
||||
try self.named_values.put("it", .{ .ptr = it_alloca, .ty = elem_ty });
|
||||
try self.named_values.put("it_index", .{ .ptr = idx_alloca, .ty = Type.s(32) });
|
||||
try self.named_values.put("it_index", .{ .ptr = idx_alloca, .ty = Type.s(64) });
|
||||
|
||||
// Create basic blocks
|
||||
const cond_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "for.cond");
|
||||
@@ -4925,13 +4964,13 @@ pub const CodeGen = struct {
|
||||
|
||||
// Condition: it_index < len
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, cond_bb);
|
||||
const cur_idx = c.LLVMBuildLoad2(self.builder, i32_type, idx_alloca, "cur_idx");
|
||||
const cur_idx = c.LLVMBuildLoad2(self.builder, i64_type, idx_alloca, "cur_idx");
|
||||
const cond_val = c.LLVMBuildICmp(self.builder, c.LLVMIntSLT, cur_idx, len_val, "for_cond");
|
||||
_ = c.LLVMBuildCondBr(self.builder, cond_val, body_bb, after_bb);
|
||||
|
||||
// Body: load it = iterable[it_index], then execute body
|
||||
c.LLVMPositionBuilderAtEnd(self.builder, body_bb);
|
||||
const body_idx = c.LLVMBuildLoad2(self.builder, i32_type, idx_alloca, "body_idx");
|
||||
const body_idx = c.LLVMBuildLoad2(self.builder, i64_type, idx_alloca, "body_idx");
|
||||
|
||||
if (is_slice) {
|
||||
// Slice: GEP through data pointer
|
||||
@@ -4942,7 +4981,7 @@ pub const CodeGen = struct {
|
||||
} else {
|
||||
// Array: GEP with [0, idx]
|
||||
const arr_llvm_ty = self.typeToLLVM(iter_ty);
|
||||
const zero = c.LLVMConstInt(i32_type, 0, 0);
|
||||
const zero = c.LLVMConstInt(i64_type, 0, 0);
|
||||
var indices = [_]c.LLVMValueRef{ zero, body_idx };
|
||||
const gep = c.LLVMBuildGEP2(self.builder, arr_llvm_ty, iter_ptr, &indices, 2, "for_elem");
|
||||
const elem_val = c.LLVMBuildLoad2(self.builder, elem_llvm_ty, gep, "it_val");
|
||||
@@ -4963,8 +5002,8 @@ pub const CodeGen = struct {
|
||||
// Increment it_index
|
||||
const current_bb = c.LLVMGetInsertBlock(self.builder);
|
||||
if (c.LLVMGetBasicBlockTerminator(current_bb) == null) {
|
||||
const inc_idx = c.LLVMBuildLoad2(self.builder, i32_type, idx_alloca, "inc_idx");
|
||||
const next_idx = c.LLVMBuildAdd(self.builder, inc_idx, c.LLVMConstInt(i32_type, 1, 0), "next_idx");
|
||||
const inc_idx = c.LLVMBuildLoad2(self.builder, i64_type, idx_alloca, "inc_idx");
|
||||
const next_idx = c.LLVMBuildAdd(self.builder, inc_idx, c.LLVMConstInt(i64_type, 1, 0), "next_idx");
|
||||
_ = c.LLVMBuildStore(self.builder, next_idx, idx_alloca);
|
||||
_ = c.LLVMBuildBr(self.builder, cond_bb);
|
||||
}
|
||||
@@ -4977,14 +5016,14 @@ pub const CodeGen = struct {
|
||||
}
|
||||
|
||||
fn genEnumLiteral(self: *CodeGen, variant_name: []const u8, enum_type_name: []const u8) c.LLVMValueRef {
|
||||
const i32_type = c.LLVMInt32TypeInContext(self.context);
|
||||
const variants = self.enum_types.get(enum_type_name) orelse return c.LLVMConstInt(i32_type, 0, 0);
|
||||
const i64_type = c.LLVMInt64TypeInContext(self.context);
|
||||
const variants = self.enum_types.get(enum_type_name) orelse return c.LLVMConstInt(i64_type, 0, 0);
|
||||
for (variants, 0..) |v, i| {
|
||||
if (std.mem.eql(u8, v, variant_name)) {
|
||||
return c.LLVMConstInt(i32_type, @intCast(i), 0);
|
||||
return c.LLVMConstInt(i64_type, @intCast(i), 0);
|
||||
}
|
||||
}
|
||||
return c.LLVMConstInt(i32_type, 0, 0);
|
||||
return c.LLVMConstInt(i64_type, 0, 0);
|
||||
}
|
||||
|
||||
fn lookupVariantIndex(variants: ?[]const []const u8, name: []const u8) u64 {
|
||||
@@ -5013,7 +5052,7 @@ pub const CodeGen = struct {
|
||||
const entry = self.named_values.get(match.subject.data.identifier.name).?;
|
||||
const info = self.union_types.get(union_name.?).?;
|
||||
const tag_gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, entry.ptr, 0, "tag");
|
||||
break :blk c.LLVMBuildLoad2(self.builder, c.LLVMInt32TypeInContext(self.context), tag_gep, "tag_val");
|
||||
break :blk c.LLVMBuildLoad2(self.builder, c.LLVMInt64TypeInContext(self.context), tag_gep, "tag_val");
|
||||
} else try self.genExpr(match.subject);
|
||||
|
||||
const variants: ?[]const []const u8 = if (union_name) |un|
|
||||
@@ -5024,7 +5063,7 @@ pub const CodeGen = struct {
|
||||
null;
|
||||
|
||||
const function = self.current_function;
|
||||
const i32_type = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_type = c.LLVMInt64TypeInContext(self.context);
|
||||
const merge_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "match_end");
|
||||
|
||||
// Create case basic blocks
|
||||
@@ -5052,19 +5091,19 @@ pub const CodeGen = struct {
|
||||
const pat = arm.pattern orelse continue; // skip else arm
|
||||
if (pat.data == .enum_literal) {
|
||||
const idx = lookupVariantIndex(variants, pat.data.enum_literal.name);
|
||||
const case_val = c.LLVMConstInt(i32_type, idx, 0);
|
||||
const case_val = c.LLVMConstInt(i64_type, idx, 0);
|
||||
c.LLVMAddCase(sw, case_val, case_bbs.items[i]);
|
||||
} else if (pat.data == .type_expr) {
|
||||
// Type-match: resolve type name to Any tag value(s)
|
||||
const tag_values = try self.resolveTypeMatchTags(pat.data.type_expr.name);
|
||||
for (tag_values) |tag| {
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(i32_type, tag, 0), case_bbs.items[i]);
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(i64_type, tag, 0), case_bbs.items[i]);
|
||||
}
|
||||
} else if (pat.data == .identifier) {
|
||||
// Named type (struct/enum/union name) or category (int/float)
|
||||
const tag_values = try self.resolveTypeMatchTags(pat.data.identifier.name);
|
||||
for (tag_values) |tag| {
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(i32_type, tag, 0), case_bbs.items[i]);
|
||||
c.LLVMAddCase(sw, c.LLVMConstInt(i64_type, tag, 0), case_bbs.items[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5179,6 +5218,8 @@ pub const CodeGen = struct {
|
||||
.array_cat
|
||||
else if (std.mem.eql(u8, name, "slice"))
|
||||
.slice_cat
|
||||
else if (std.mem.eql(u8, name, "pointer"))
|
||||
.pointer_cat
|
||||
else
|
||||
null;
|
||||
if (category) |cat| {
|
||||
@@ -5208,7 +5249,7 @@ pub const CodeGen = struct {
|
||||
ANY_TAG_F64
|
||||
else if (std.mem.eql(u8, name, "string"))
|
||||
ANY_TAG_STRING
|
||||
else if (std.mem.eql(u8, name, "Type"))
|
||||
else if (std.mem.eql(u8, name, "Type") or std.mem.eql(u8, name, "type"))
|
||||
ANY_TAG_TYPE
|
||||
else if (std.mem.eql(u8, name, "void"))
|
||||
ANY_TAG_VOID
|
||||
@@ -5303,7 +5344,9 @@ pub const CodeGen = struct {
|
||||
const val = try self.genExpr(args[0]);
|
||||
// Extract ptr and len from string slice
|
||||
const ptr = c.LLVMBuildExtractValue(self.builder, val, 0, "str_ptr");
|
||||
const len = c.LLVMBuildExtractValue(self.builder, val, 1, "str_len");
|
||||
const len_i64 = c.LLVMBuildExtractValue(self.builder, val, 1, "str_len");
|
||||
// printf %.*s precision is C int (i32) — truncate from i64
|
||||
const len = c.LLVMBuildTrunc(self.builder, len_i64, c.LLVMInt32TypeInContext(self.context), "len_trunc");
|
||||
const fmt = c.LLVMBuildGlobalStringPtr(self.builder, "%.*s", "write_fmt");
|
||||
const printf_fn = builtins.printf_fn;
|
||||
const fn_type = c.LLVMGlobalGetValueType(printf_fn);
|
||||
@@ -5322,7 +5365,7 @@ pub const CodeGen = struct {
|
||||
/// Helper: build a constant string slice as a global constant (no builder needed).
|
||||
fn buildConstStrGlobal(self: *CodeGen, s: []const u8) c.LLVMValueRef {
|
||||
const sz = self.allocator.dupeZ(u8, s) catch unreachable;
|
||||
const i32_ty = c.LLVMInt32TypeInContext(self.context);
|
||||
const i64_ty = c.LLVMInt64TypeInContext(self.context);
|
||||
const i8_ty = c.LLVMInt8TypeInContext(self.context);
|
||||
// Create a global string constant
|
||||
const str_const = c.LLVMConstStringInContext(self.context, sz.ptr, @intCast(s.len), 0);
|
||||
@@ -5335,10 +5378,10 @@ pub const CodeGen = struct {
|
||||
c.LLVMSetGlobalConstant(global, 1);
|
||||
c.LLVMSetLinkage(global, c.LLVMPrivateLinkage);
|
||||
}
|
||||
// Build constant struct {ptr, i32}
|
||||
// Build constant struct {ptr, i64}
|
||||
var fields = [_]c.LLVMValueRef{
|
||||
c.LLVMConstBitCast(global.?, c.LLVMPointerTypeInContext(self.context, 0)),
|
||||
c.LLVMConstInt(i32_ty, s.len, 0),
|
||||
c.LLVMConstInt(i64_ty, s.len, 0),
|
||||
};
|
||||
return c.LLVMConstStructInContext(self.context, &fields, 2, 0);
|
||||
}
|
||||
@@ -5368,6 +5411,43 @@ pub const CodeGen = struct {
|
||||
return self.allocator.dupeZ(u8, name) catch unreachable;
|
||||
}
|
||||
|
||||
/// Convert a type expression AST node to its source string representation.
|
||||
fn typeNodeToString(self: *CodeGen, node: *const Node) []const u8 {
|
||||
return switch (node.data) {
|
||||
.type_expr => |te| te.name,
|
||||
.identifier => |id| id.name,
|
||||
.pointer_type_expr => |pte| std.fmt.allocPrint(self.allocator, "*{s}", .{self.typeNodeToString(pte.pointee_type)}) catch "?",
|
||||
.many_pointer_type_expr => |mpte| std.fmt.allocPrint(self.allocator, "[*]{s}", .{self.typeNodeToString(mpte.element_type)}) catch "?",
|
||||
.slice_type_expr => |ste| std.fmt.allocPrint(self.allocator, "[]{s}", .{self.typeNodeToString(ste.element_type)}) catch "?",
|
||||
.array_type_expr => |ate| blk: {
|
||||
const elem = self.typeNodeToString(ate.element_type);
|
||||
if (ate.length.data == .int_literal) {
|
||||
break :blk std.fmt.allocPrint(self.allocator, "[{d}]{s}", .{ ate.length.data.int_literal.value, elem }) catch "?";
|
||||
}
|
||||
break :blk std.fmt.allocPrint(self.allocator, "[?]{s}", .{elem}) catch "?";
|
||||
},
|
||||
else => "?",
|
||||
};
|
||||
}
|
||||
|
||||
/// Build a function type string like "() -> s32" from an fn_decl.
|
||||
fn buildFnSignature(self: *CodeGen, fd: ast.FnDecl) []const u8 {
|
||||
var buf = std.ArrayList(u8).empty;
|
||||
buf.appendSlice(self.allocator, "(") catch return "?";
|
||||
for (fd.params, 0..) |param, i| {
|
||||
if (i > 0) buf.appendSlice(self.allocator, ", ") catch {};
|
||||
if (param.is_variadic) buf.appendSlice(self.allocator, "..") catch {};
|
||||
const ty_str = self.typeNodeToString(param.type_expr);
|
||||
buf.appendSlice(self.allocator, ty_str) catch {};
|
||||
}
|
||||
buf.appendSlice(self.allocator, ")") catch {};
|
||||
if (fd.return_type) |rt| {
|
||||
buf.appendSlice(self.allocator, " -> ") catch {};
|
||||
buf.appendSlice(self.allocator, self.typeNodeToString(rt)) catch {};
|
||||
}
|
||||
return buf.toOwnedSlice(self.allocator) catch "?";
|
||||
}
|
||||
|
||||
/// Extract a qualified name from a callee expression (identifier or field_access chain).
|
||||
fn calleeToQualifiedName(self: *CodeGen, callee: *Node) ?[]const u8 {
|
||||
if (callee.data == .identifier) return callee.data.identifier.name;
|
||||
@@ -5415,7 +5495,7 @@ pub const CodeGen = struct {
|
||||
|
||||
fn inferType(self: *CodeGen, node: *Node) Type {
|
||||
return switch (node.data) {
|
||||
.int_literal => Type.s(32),
|
||||
.int_literal => Type.s(64),
|
||||
.float_literal => .f32,
|
||||
.bool_literal => .boolean,
|
||||
.string_literal => .string_type,
|
||||
@@ -5435,7 +5515,7 @@ pub const CodeGen = struct {
|
||||
.identifier => |ident| {
|
||||
if (self.named_values.get(ident.name)) |entry| return entry.ty;
|
||||
if (self.comptime_globals.get(ident.name)) |ct| return ct.ty;
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
},
|
||||
.if_expr => |ie| {
|
||||
return self.inferType(ie.then_branch);
|
||||
@@ -5477,21 +5557,21 @@ pub const CodeGen = struct {
|
||||
};
|
||||
if (obj_ty) |uty| return uty;
|
||||
}
|
||||
const callee_name = self.resolveCalleeName(call_node) orelse return Type.s(32);
|
||||
const callee_name = self.resolveCalleeName(call_node) orelse return Type.s(64);
|
||||
const base_name = if (std.mem.lastIndexOfScalar(u8, callee_name, '.')) |idx| callee_name[idx + 1 ..] else callee_name;
|
||||
// Built-in: sqrt returns same type as argument
|
||||
if (std.mem.eql(u8, base_name, "sqrt")) {
|
||||
if (call_node.args.len > 0) return self.inferType(call_node.args[0]);
|
||||
return .f32;
|
||||
}
|
||||
// Built-in: size_of returns s32
|
||||
if (std.mem.eql(u8, base_name, "size_of")) return Type.s(32);
|
||||
// Built-in: type_of returns s32 (type tag)
|
||||
if (std.mem.eql(u8, base_name, "type_of")) return Type.s(32);
|
||||
// Built-in: size_of returns s64
|
||||
if (std.mem.eql(u8, base_name, "size_of")) return Type.s(64);
|
||||
// Built-in: type_of returns s64 (type tag)
|
||||
if (std.mem.eql(u8, base_name, "type_of")) return Type.s(64);
|
||||
// Built-in: type_name returns string
|
||||
if (std.mem.eql(u8, base_name, "type_name")) return .string_type;
|
||||
// Built-in: field_count returns s32
|
||||
if (std.mem.eql(u8, base_name, "field_count")) return Type.s(32);
|
||||
// Built-in: field_count returns s64
|
||||
if (std.mem.eql(u8, base_name, "field_count")) return Type.s(64);
|
||||
// Built-in: field_name returns string
|
||||
if (std.mem.eql(u8, base_name, "field_name")) return .string_type;
|
||||
// Built-in: field_value returns Any
|
||||
@@ -5499,7 +5579,7 @@ pub const CodeGen = struct {
|
||||
// Built-in: cast returns the target type (first arg)
|
||||
if (std.mem.eql(u8, base_name, "cast")) {
|
||||
if (call_node.args.len > 0) return self.resolveType(call_node.args[0]);
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
}
|
||||
// Built-in: alloc returns string
|
||||
if (std.mem.eql(u8, base_name, "alloc")) return .string_type;
|
||||
@@ -5507,7 +5587,7 @@ pub const CodeGen = struct {
|
||||
const template = self.generic_templates.get(callee_name) orelse blk: {
|
||||
// Intra-namespace fallback
|
||||
if (self.current_namespace) |ns| {
|
||||
const qualified = std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns, callee_name }) catch return Type.s(32);
|
||||
const qualified = std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns, callee_name }) catch return Type.s(64);
|
||||
break :blk self.generic_templates.get(qualified);
|
||||
}
|
||||
break :blk null;
|
||||
@@ -5544,16 +5624,16 @@ pub const CodeGen = struct {
|
||||
const resolved = self.resolveType(rt);
|
||||
if (!std.meta.eql(resolved, Type.void_type)) return resolved;
|
||||
}
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
}
|
||||
// Check non-generic LLVM functions
|
||||
const callee_name_z = self.allocator.dupeZ(u8, callee_name) catch return Type.s(32);
|
||||
const callee_name_z = self.allocator.dupeZ(u8, callee_name) catch return Type.s(64);
|
||||
var callee_fn_opt = c.LLVMGetNamedFunction(self.module, callee_name_z.ptr);
|
||||
// Intra-namespace fallback
|
||||
if (callee_fn_opt == null) {
|
||||
if (self.current_namespace) |ns| {
|
||||
const q = std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns, callee_name }) catch return Type.s(32);
|
||||
const qz = self.allocator.dupeZ(u8, q) catch return Type.s(32);
|
||||
const q = std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ ns, callee_name }) catch return Type.s(64);
|
||||
const qz = self.allocator.dupeZ(u8, q) catch return Type.s(64);
|
||||
callee_fn_opt = c.LLVMGetNamedFunction(self.module, qz.ptr);
|
||||
}
|
||||
}
|
||||
@@ -5562,44 +5642,44 @@ pub const CodeGen = struct {
|
||||
const ret_llvm = c.LLVMGetReturnType(fn_type);
|
||||
return self.llvmTypeToSxType(ret_llvm);
|
||||
}
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
},
|
||||
.unary_op => |unop| {
|
||||
if (unop.op == .address_of) {
|
||||
const operand_ty = self.inferType(unop.operand);
|
||||
const name = operand_ty.displayName(self.allocator) catch return Type.s(32);
|
||||
const name = operand_ty.displayName(self.allocator) catch return Type.s(64);
|
||||
return .{ .pointer_type = .{ .pointee_name = name } };
|
||||
}
|
||||
return self.inferType(unop.operand);
|
||||
},
|
||||
.deref_expr => |de| {
|
||||
const ptr_ty = self.inferType(de.operand);
|
||||
if (ptr_ty.isPointer()) return self.resolveTypeFromName(ptr_ty.pointer_type.pointee_name) orelse Type.s(32);
|
||||
return Type.s(32);
|
||||
if (ptr_ty.isPointer()) return self.resolveTypeFromName(ptr_ty.pointer_type.pointee_name) orelse Type.s(64);
|
||||
return Type.s(64);
|
||||
},
|
||||
.null_literal => return .{ .pointer_type = .{ .pointee_name = "void" } },
|
||||
.field_access => |fa| {
|
||||
var obj_ty = self.inferType(fa.object);
|
||||
// Auto-deref: if pointer, unwrap to pointee
|
||||
if (obj_ty.isPointer()) {
|
||||
obj_ty = self.resolveTypeFromName(obj_ty.pointer_type.pointee_name) orelse Type.s(32);
|
||||
obj_ty = self.resolveTypeFromName(obj_ty.pointer_type.pointee_name) orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty == .string_type) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(32);
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(64);
|
||||
if (std.mem.eql(u8, fa.field, "ptr")) return .string_type;
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(32);
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(64);
|
||||
}
|
||||
if (obj_ty.isArray()) {
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(32);
|
||||
if (std.mem.eql(u8, fa.field, "len")) return Type.s(64);
|
||||
}
|
||||
if (obj_ty.isAny()) {
|
||||
if (std.mem.eql(u8, fa.field, "tag")) return Type.s(32);
|
||||
if (std.mem.eql(u8, fa.field, "tag")) return Type.s(64);
|
||||
if (std.mem.eql(u8, fa.field, "value")) return Type.s(64);
|
||||
}
|
||||
if (obj_ty.isVector()) {
|
||||
return obj_ty.vectorElementType() orelse Type.s(32);
|
||||
return obj_ty.vectorElementType() orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isStruct()) {
|
||||
if (self.struct_types.get(obj_ty.struct_type)) |info| {
|
||||
@@ -5617,23 +5697,24 @@ pub const CodeGen = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
},
|
||||
.index_expr => |ie| {
|
||||
const obj_ty = self.inferType(ie.object);
|
||||
if (obj_ty == .string_type) return Type.u(8);
|
||||
if (obj_ty.isVector()) {
|
||||
return obj_ty.vectorElementType() orelse Type.s(32);
|
||||
return obj_ty.vectorElementType() orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isArray()) {
|
||||
return Type.fromName(obj_ty.array_type.element_name) orelse Type.s(32);
|
||||
return Type.fromName(obj_ty.array_type.element_name) orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isSlice()) {
|
||||
return obj_ty.sliceElementType() orelse Type.s(32);
|
||||
return obj_ty.sliceElementType() orelse Type.s(64);
|
||||
}
|
||||
if (obj_ty.isManyPointer()) {
|
||||
return self.resolveTypeFromName(obj_ty.many_pointer_type.element_name) orelse Type.s(32);
|
||||
return self.resolveTypeFromName(obj_ty.many_pointer_type.element_name) orelse Type.s(64);
|
||||
}
|
||||
return Type.s(32);
|
||||
return Type.s(64);
|
||||
},
|
||||
.slice_expr => |se| {
|
||||
const obj_ty = self.inferType(se.object);
|
||||
@@ -5645,11 +5726,11 @@ pub const CodeGen = struct {
|
||||
.array_literal => |al| {
|
||||
if (al.elements.len == 0) return .void_type;
|
||||
const elem_ty = self.inferType(al.elements[0]);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(32);
|
||||
const elem_name = elem_ty.displayName(self.allocator) catch return Type.s(64);
|
||||
return .{ .array_type = .{ .element_name = elem_name, .length = @intCast(al.elements.len) } };
|
||||
},
|
||||
.while_expr, .for_expr, .break_expr, .continue_expr => .void_type,
|
||||
else => Type.s(32),
|
||||
else => Type.s(64),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user