From 476bf0d268850699b6bd60f7eca13b104b0c0bfb Mon Sep 17 00:00:00 2001 From: agra Date: Sun, 15 Feb 2026 11:35:47 +0200 Subject: [PATCH] clean --- src/codegen.zig | 564 ++++++++++++++++++++++++++--------------------- src/comptime.zig | 6 +- src/sema.zig | 6 +- 3 files changed, 317 insertions(+), 259 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index bea1515..c9a5c20 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -95,6 +95,10 @@ pub const TargetConfig = struct { } }; +fn baseName(name: []const u8) []const u8 { + return if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; +} + pub const CodeGen = struct { context: c.LLVMContextRef, module: c.LLVMModuleRef, @@ -549,7 +553,7 @@ pub const CodeGen = struct { fn buildAnyValue(self: *CodeGen, val: c.LLVMValueRef, in_ty: Type) !c.LLVMValueRef { const any_ty = self.getAnyStructType(); const i64_ty = self.i64Type(); - const undef = c.LLVMGetUndef(any_ty); + const undef = self.getUndef(any_ty); // []u8 boxes as string (same repr, same Any tag) const ty: Type = if (in_ty.isSlice() and std.mem.eql(u8, in_ty.slice_type.element_name, "u8")) @@ -578,80 +582,54 @@ pub const CodeGen = struct { else => ANY_TAG_S32, }; const tag_val = c.LLVMConstInt(i64_ty, tag, 0); - const with_tag = c.LLVMBuildInsertValue(self.builder, undef, tag_val, 0, "any_tag"); + const with_tag = self.insertValue(undef, tag_val, 0, "any_tag"); // Convert value to i64 const val_as_i64 = switch (ty) { - .boolean => c.LLVMBuildZExt(self.builder, val, i64_ty, "any_bool"), + .boolean => self.zExt(val, i64_ty, "any_bool"), .signed => |w| if (w <= 32) - c.LLVMBuildSExt(self.builder, val, i64_ty, "any_int") + self.sExt(val, i64_ty, "any_int") else val, .unsigned => |w| if (w <= 32) - c.LLVMBuildZExt(self.builder, val, i64_ty, "any_uint") + self.zExt(val, i64_ty, "any_uint") else val, .f32 => blk: { // f32 -> f64 -> bitcast to i64 const as_f64 = c.LLVMBuildFPExt(self.builder, val, self.f64Type(), "f32_to_f64"); - break :blk c.LLVMBuildBitCast(self.builder, as_f64, i64_ty, "any_f32"); - }, - .f64 => c.LLVMBuildBitCast(self.builder, val, i64_ty, "any_f64"), - .string_type => blk: { - // String is {ptr, i32} — store to alloca, pass alloca as i64 - const str_alloca = self.buildEntryBlockAlloca(self.getStringStructType(), "any_str_tmp"); - _ = c.LLVMBuildStore(self.builder, val, str_alloca); - break :blk c.LLVMBuildPtrToInt(self.builder, str_alloca, i64_ty, "any_str"); + break :blk self.bitCast(as_f64, i64_ty, "any_f32"); }, + .f64 => self.bitCast(val, i64_ty, "any_f64"), + .string_type => self.allocaStoreAsI64(self.getStringStructType(), val, "any_str"), .struct_type => |sname| blk: { // Struct — store to alloca, pass pointer as i64 const info = self.struct_types.get(sname) orelse - return c.LLVMGetUndef(any_ty); - const alloca = self.buildEntryBlockAlloca(info.llvm_type, "any_struct_tmp"); - _ = c.LLVMBuildStore(self.builder, val, alloca); - break :blk c.LLVMBuildPtrToInt(self.builder, alloca, i64_ty, "any_struct"); + return self.getUndef(any_ty); + break :blk self.allocaStoreAsI64(info.llvm_type, val, "any_struct"); }, .enum_type => |ename| blk: { // Enum — extend to i64 for Any storage (no-op if already i64) const enum_llvm_ty = self.getEnumLLVMType(ename); const enum_bits = c.LLVMGetIntTypeWidth(enum_llvm_ty); if (enum_bits < 64) - break :blk c.LLVMBuildZExt(self.builder, val, i64_ty, "any_enum") + break :blk self.zExt(val, i64_ty, "any_enum") else break :blk val; }, .union_type => |uname| blk: { // Union — store to alloca, pass pointer as i64 const info = self.tagged_enum_types.get(uname) orelse - return c.LLVMGetUndef(any_ty); - const alloca = self.buildEntryBlockAlloca(info.llvm_type, "any_union_tmp"); - _ = c.LLVMBuildStore(self.builder, val, alloca); - break :blk c.LLVMBuildPtrToInt(self.builder, alloca, i64_ty, "any_union"); + return self.getUndef(any_ty); + break :blk self.allocaStoreAsI64(info.llvm_type, val, "any_union"); }, - .vector_type, .array_type => blk: { - // Vector/Array — store to alloca, pass pointer as i64 - const llvm_ty = self.typeToLLVM(ty); - const alloca = self.buildEntryBlockAlloca(llvm_ty, "any_vec_tmp"); - _ = c.LLVMBuildStore(self.builder, val, alloca); - break :blk c.LLVMBuildPtrToInt(self.builder, alloca, i64_ty, "any_vec"); - }, - .slice_type => blk: { - // Slice {ptr, i32} — store to alloca, pass pointer as i64 - const alloca = self.buildEntryBlockAlloca(self.getStringStructType(), "any_slice_tmp"); - _ = c.LLVMBuildStore(self.builder, val, alloca); - 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 => |mt| blk: { - // Meta type: wrap raw char ptr in string slice {ptr, len} for extraction - const str_slice = self.buildStringSlice(val, self.constInt64(mt.name.len)); - const alloca = self.buildEntryBlockAlloca(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"), + .vector_type, .array_type => self.allocaStoreAsI64(self.typeToLLVM(ty), val, "any_vec"), + .slice_type => self.allocaStoreAsI64(self.getStringStructType(), val, "any_slice"), + .pointer_type, .many_pointer_type => self.ptrToInt(val, "any_ptr"), + .meta_type => |mt| self.allocaStoreAsI64(self.getStringStructType(), self.buildStringSlice(val, self.constInt64(mt.name.len)), "any_type"), + else => self.sExt(val, i64_ty, "any_val"), }; - return c.LLVMBuildInsertValue(self.builder, with_tag, val_as_i64, 1, "any_value"); + return self.insertValue(with_tag, val_as_i64, 1, "any_value"); } fn getStringStructType(self: *CodeGen) c.LLVMTypeRef { @@ -666,9 +644,9 @@ pub const CodeGen = struct { /// Build a fat pointer {ptr, len} struct from a type, pointer, and length value. fn buildFatPointer(self: *CodeGen, ty: c.LLVMTypeRef, ptr: c.LLVMValueRef, len: c.LLVMValueRef) c.LLVMValueRef { - const undef = c.LLVMGetUndef(ty); - const with_ptr = c.LLVMBuildInsertValue(self.builder, undef, ptr, 0, "ptr"); - return c.LLVMBuildInsertValue(self.builder, with_ptr, len, 1, "len"); + const undef = self.getUndef(ty); + const with_ptr = self.insertValue(undef, ptr, 0, "ptr"); + return self.insertValue(with_ptr, len, 1, "len"); } /// Build a string slice {ptr, len} from a raw pointer and a length value. @@ -702,18 +680,20 @@ pub const CodeGen = struct { return c.LLVMBuildGEP2(self.builder, arr_ty, arr_ptr, &indices, 2, name); } + fn structGEP(self: *CodeGen, struct_ty: c.LLVMTypeRef, ptr: c.LLVMValueRef, idx: c_uint, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildStructGEP2(self.builder, struct_ty, ptr, idx, name); + } + fn storeStructField(self: *CodeGen, struct_ty: c.LLVMTypeRef, ptr: c.LLVMValueRef, field_idx: c_uint, val: c.LLVMValueRef) void { - const gep = c.LLVMBuildStructGEP2(self.builder, struct_ty, ptr, field_idx, "field"); - _ = c.LLVMBuildStore(self.builder, val, gep); + _ = c.LLVMBuildStore(self.builder, val, self.structGEP(struct_ty, ptr, field_idx, "field")); } fn loadStructField(self: *CodeGen, struct_ty: c.LLVMTypeRef, ptr: c.LLVMValueRef, field_idx: c_uint, field_ty: c.LLVMTypeRef) c.LLVMValueRef { - const gep = c.LLVMBuildStructGEP2(self.builder, struct_ty, ptr, field_idx, "field"); - return c.LLVMBuildLoad2(self.builder, field_ty, gep, "fieldval"); + return c.LLVMBuildLoad2(self.builder, field_ty, self.structGEP(struct_ty, ptr, field_idx, "field"), "fieldval"); } fn storeUndef(self: *CodeGen, ty: c.LLVMTypeRef, ptr: c.LLVMValueRef) void { - _ = c.LLVMBuildStore(self.builder, c.LLVMGetUndef(ty), ptr); + _ = c.LLVMBuildStore(self.builder, self.getUndef(ty), ptr); } fn storeNull(self: *CodeGen, ty: c.LLVMTypeRef, ptr: c.LLVMValueRef) void { @@ -731,8 +711,8 @@ pub const CodeGen = struct { }; fn buildSwitch(self: *CodeGen, cond: c.LLVMValueRef, case_count: c_uint, merge_name: [*c]const u8, default_name: [*c]const u8) SwitchBlock { - const merge_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, merge_name); - const default_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, default_name); + const merge_bb = self.appendBB(merge_name); + const default_bb = self.appendBB(default_name); const sw = c.LLVMBuildSwitch(self.builder, cond, default_bb, case_count); return .{ .merge_bb = merge_bb, .default_bb = default_bb, .sw = sw }; } @@ -745,7 +725,7 @@ pub const CodeGen = struct { } fn loadFromI64Ptr(self: *CodeGen, i64_val: c.LLVMValueRef, ty: c.LLVMTypeRef, name: [*c]const u8) c.LLVMValueRef { - const ptr = c.LLVMBuildIntToPtr(self.builder, i64_val, self.ptrType(), name); + const ptr = self.intToPtr(i64_val, name); return c.LLVMBuildLoad2(self.builder, ty, ptr, name); } @@ -763,8 +743,8 @@ pub const CodeGen = struct { fn addPhiCase(self: *CodeGen, phi_vals: *std.ArrayList(c.LLVMValueRef), phi_bbs: *std.ArrayList(c.LLVMBasicBlockRef), val: c.LLVMValueRef, merge_bb: c.LLVMBasicBlockRef) !void { try phi_vals.append(self.allocator, val); - try phi_bbs.append(self.allocator, c.LLVMGetInsertBlock(self.builder)); - _ = c.LLVMBuildBr(self.builder, merge_bb); + try phi_bbs.append(self.allocator, self.getCurrentBlock()); + self.br(merge_bb); } fn getTypeSize(self: *CodeGen, ty: c.LLVMTypeRef) u64 { @@ -773,13 +753,13 @@ pub const CodeGen = struct { fn appendBlock(self: *CodeGen, function: c.LLVMValueRef, name: [*c]const u8) c.LLVMBasicBlockRef { const bb = c.LLVMAppendBasicBlockInContext(self.context, function, name); - c.LLVMPositionBuilderAtEnd(self.builder, bb); + self.positionAt(bb); return bb; } fn valueToBool(self: *CodeGen, val: c.LLVMValueRef) c.LLVMValueRef { if (c.LLVMTypeOf(val) == self.i1Type()) return val; - return c.LLVMBuildICmp(self.builder, c.LLVMIntNE, val, c.LLVMConstInt(c.LLVMTypeOf(val), 0, 0), "tobool"); + return self.icmp(c.LLVMIntNE, val, c.LLVMConstInt(c.LLVMTypeOf(val), 0, 0), "tobool"); } fn constInt64(self: *CodeGen, val: u64) c.LLVMValueRef { @@ -790,13 +770,91 @@ pub const CodeGen = struct { return c.LLVMConstInt(self.i32Type(), val, 0); } + fn extractValue(self: *CodeGen, val: c.LLVMValueRef, idx: c_uint, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildExtractValue(self.builder, val, idx, name); + } + + fn buildGlobalString(self: *CodeGen, str: [*c]const u8, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildGlobalStringPtr(self.builder, str, name); + } + + fn insertValue(self: *CodeGen, aggr: c.LLVMValueRef, val: c.LLVMValueRef, idx: c_uint, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildInsertValue(self.builder, aggr, val, idx, name); + } + + fn positionAt(self: *CodeGen, bb: c.LLVMBasicBlockRef) void { + c.LLVMPositionBuilderAtEnd(self.builder, bb); + } + + fn br(self: *CodeGen, dest: c.LLVMBasicBlockRef) void { + _ = c.LLVMBuildBr(self.builder, dest); + } + + fn condBr(self: *CodeGen, cond: c.LLVMValueRef, then_bb: c.LLVMBasicBlockRef, else_bb: c.LLVMBasicBlockRef) void { + _ = c.LLVMBuildCondBr(self.builder, cond, then_bb, else_bb); + } + + fn allocaStoreAsI64(self: *CodeGen, ty: c.LLVMTypeRef, val: c.LLVMValueRef, name: [*c]const u8) c.LLVMValueRef { + const alloca = self.buildEntryBlockAlloca(ty, name); + _ = c.LLVMBuildStore(self.builder, val, alloca); + return self.ptrToInt(alloca, name); + } + + fn trunc(self: *CodeGen, val: c.LLVMValueRef, ty: c.LLVMTypeRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildTrunc(self.builder, val, ty, name); + } + + fn zExt(self: *CodeGen, val: c.LLVMValueRef, ty: c.LLVMTypeRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildZExt(self.builder, val, ty, name); + } + + fn sExt(self: *CodeGen, val: c.LLVMValueRef, ty: c.LLVMTypeRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildSExt(self.builder, val, ty, name); + } + + fn bitCast(self: *CodeGen, val: c.LLVMValueRef, ty: c.LLVMTypeRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildBitCast(self.builder, val, ty, name); + } + + fn appendBB(self: *CodeGen, name: [*c]const u8) c.LLVMBasicBlockRef { + return c.LLVMAppendBasicBlockInContext(self.context, self.current_function, name); + } + + fn getCurrentBlock(self: *CodeGen) c.LLVMBasicBlockRef { + return c.LLVMGetInsertBlock(self.builder); + } + + fn ret(self: *CodeGen, val: c.LLVMValueRef) void { + _ = c.LLVMBuildRet(self.builder, val); + } + + fn retVoid(self: *CodeGen) void { + _ = c.LLVMBuildRetVoid(self.builder); + } + + fn intToPtr(self: *CodeGen, val: c.LLVMValueRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildIntToPtr(self.builder, val, self.ptrType(), name); + } + + fn ptrToInt(self: *CodeGen, ptr: c.LLVMValueRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildPtrToInt(self.builder, ptr, self.i64Type(), name); + } + + fn icmp(self: *CodeGen, pred: c.LLVMIntPredicate, lhs: c.LLVMValueRef, rhs: c.LLVMValueRef, name: [*c]const u8) c.LLVMValueRef { + return c.LLVMBuildICmp(self.builder, pred, lhs, rhs, name); + } + + fn getUndef(_: *CodeGen, ty: c.LLVMTypeRef) c.LLVMValueRef { + return c.LLVMGetUndef(ty); + } + /// Extract .len or .ptr from a fat pointer value ({ptr, len} struct). fn extractFatPtrField(self: *CodeGen, val: c.LLVMValueRef, field: []const u8, type_name: []const u8) !c.LLVMValueRef { if (std.mem.eql(u8, field, "len")) { - return c.LLVMBuildExtractValue(self.builder, val, 1, "len"); + return self.extractValue(val, 1, "len"); } if (std.mem.eql(u8, field, "ptr")) { - return c.LLVMBuildExtractValue(self.builder, val, 0, "ptr"); + return self.extractValue(val, 0, "ptr"); } return self.emitErrorFmt("no field '{s}' on {s} (available: .len, .ptr)", .{ field, type_name }); } @@ -1137,7 +1195,7 @@ pub const CodeGen = struct { .bool_val => |v| c.LLVMConstInt(self.i1Type(), if (v) 1 else 0, 0), .string_val => |v| blk: { const z = self.allocator.dupeZ(u8, v) catch unreachable; - const ptr = c.LLVMBuildGlobalStringPtr(self.builder, z.ptr, "comptime_str"); + const ptr = self.buildGlobalString(z.ptr, "comptime_str"); break :blk self.buildStringSlice(ptr, self.constInt64(@intCast(v.len))); }, .void_val => self.constInt32(0), @@ -2006,7 +2064,7 @@ pub const CodeGen = struct { const name_z = try self.allocator.dupeZ(u8, vd.name); const global = c.LLVMAddGlobal(self.module, llvm_ty, name_z.ptr); // Initialize with undef (will be set at runtime, e.g. by load_gl) - c.LLVMSetInitializer(global, c.LLVMGetUndef(llvm_ty)); + c.LLVMSetInitializer(global, self.getUndef(llvm_ty)); // NOT constant — this is a mutable global c.LLVMSetGlobalConstant(global, 0); @@ -2080,7 +2138,7 @@ pub const CodeGen = struct { } // Return — skip if current block already has a terminator (from explicit return) - const current_bb = c.LLVMGetInsertBlock(self.builder); + const current_bb = self.getCurrentBlock(); if (c.LLVMGetBasicBlockTerminator(current_bb) == null) { // Implicit return path: pop scope (executes defers) then return try self.popScope(); @@ -2091,16 +2149,16 @@ pub const CodeGen = struct { null; if (ret_sx_type == .void_type and !is_main) { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } else if (effective_last_val) |val| { const ret_val = try self.prepareReturnValue(val, ret_sx_type); - _ = c.LLVMBuildRet(self.builder, ret_val); + self.ret(ret_val); } else if (is_main) { - _ = c.LLVMBuildRet(self.builder, c.LLVMConstInt(ret_llvm_type, 0, 0)); + self.ret(c.LLVMConstInt(ret_llvm_type, 0, 0)); } else if (ret_sx_type != .void_type) { _ = c.LLVMBuildUnreachable(self.builder); } else { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } } else { // Explicit return already emitted defers; just clean up scope stacks @@ -2152,9 +2210,9 @@ pub const CodeGen = struct { if (ret_val) |val| { const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val)); const converted = self.convertValue(val, src_ty, ret_sx_type); - _ = c.LLVMBuildRet(self.builder, converted); + self.ret(converted); } else { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } } @@ -2176,7 +2234,7 @@ pub const CodeGen = struct { // Non-generic local function // Save outer function state const saved_fn = self.current_function; - const saved_bb = c.LLVMGetInsertBlock(self.builder); + const saved_bb = self.getCurrentBlock(); const saved_ret = self.current_return_type; const saved_named = self.named_values; self.named_values = std.StringHashMap(NamedValue).init(self.allocator); @@ -2207,16 +2265,16 @@ pub const CodeGen = struct { last_val = try self.genExpr(fd.body); } - const current_bb2 = c.LLVMGetInsertBlock(self.builder); + const current_bb2 = self.getCurrentBlock(); if (c.LLVMGetBasicBlockTerminator(current_bb2) == null) { if (ret_sx_type == .void_type) { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } else if (last_val) |val| { const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val)); const converted = self.convertValue(val, src_ty, ret_sx_type); - _ = c.LLVMBuildRet(self.builder, converted); + self.ret(converted); } else { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } } @@ -2224,7 +2282,7 @@ pub const CodeGen = struct { self.named_values = saved_named; self.current_return_type = saved_ret; self.current_function = saved_fn; - c.LLVMPositionBuilderAtEnd(self.builder, saved_bb); + self.positionAt(saved_bb); } return null; }, @@ -2245,10 +2303,10 @@ pub const CodeGen = struct { const raw_val = try self.genExpr(val_node); const ret_val = try self.prepareReturnValue(raw_val, self.current_return_type); try self.emitAllDefers(); - _ = c.LLVMBuildRet(self.builder, ret_val); + self.ret(ret_val); } else { try self.emitAllDefers(); - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } // Create a dead basic block for any subsequent instructions _ = self.appendBlock(self.current_function, "after_ret"); @@ -2294,7 +2352,7 @@ pub const CodeGen = struct { const name_z = try self.allocator.dupeZ(u8, vd.name); const ptr_ty = self.ptrType(); const alloca = self.buildEntryBlockAlloca(ptr_ty, name_z.ptr); - const str_val = c.LLVMBuildGlobalStringPtr(self.builder, type_name.ptr, "type_name"); + const str_val = self.buildGlobalString(type_name.ptr, "type_name"); _ = c.LLVMBuildStore(self.builder, str_val, alloca); try self.registerVariable(vd.name, alloca, .{ .meta_type = .{ .name = raw_name } }); return null; @@ -2523,7 +2581,7 @@ pub const CodeGen = struct { for (info.field_names, 0..) |_, fi| { const ft = info.field_types[fi]; const ft_llvm = self.typeToLLVM(ft); - const gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, alloca, @intCast(fi), "dinit"); + const gep = self.structGEP(info.llvm_type, alloca, @intCast(fi), "dinit"); if (info.field_defaults.len > fi and info.field_defaults[fi] != null) { const default_node = info.field_defaults[fi].?; @@ -2666,7 +2724,7 @@ pub const CodeGen = struct { }; 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"); + const str_val = self.buildGlobalString(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 = rn } }; @@ -2733,7 +2791,7 @@ pub const CodeGen = struct { const field_ty = info.field_types[fi]; const loaded_ptr = c.LLVMBuildLoad2(self.builder, self.ptrType(), entry.ptr, "ptr_load"); - const gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, loaded_ptr, @intCast(fi), "pfield_ptr"); + const gep = self.structGEP(info.llvm_type, loaded_ptr, @intCast(fi), "pfield_ptr"); const rhs = try self.genExprAsType(asgn.value, field_ty); self.storeOrCompound(asgn.op, gep, rhs, field_ty, "pcur"); return null; @@ -2754,7 +2812,7 @@ pub const CodeGen = struct { // Check promoted fields from anonymous structs if (info.promoted_fields.get(fa.field)) |pf| { const sinfo = try self.getStructInfo(pf.struct_name); - const gep = c.LLVMBuildStructGEP2(self.builder, sinfo.llvm_type, entry.ptr, @intCast(pf.field_index), "promoted_ptr"); + const gep = self.structGEP(sinfo.llvm_type, entry.ptr, @intCast(pf.field_index), "promoted_ptr"); const rhs = try self.genExprAsType(asgn.value, pf.field_type); self.storeOrCompound(asgn.op, gep, rhs, pf.field_type, "ucur"); return null; @@ -2771,7 +2829,7 @@ pub const CodeGen = struct { const fi = try self.findFieldIndex(info.field_names, fa.field, sname); const field_ty = info.field_types[fi]; - const gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, entry.ptr, @intCast(fi), "fassign"); + const gep = self.structGEP(info.llvm_type, entry.ptr, @intCast(fi), "fassign"); // Generate RHS and convert to field type const rhs = try self.genExprAsType(asgn.value, field_ty); @@ -2785,12 +2843,12 @@ pub const CodeGen = struct { if (obj_ty == .string_type) { // String index assignment: s[i] = c const str_val = try self.genExpr(ie.object); - const ptr = c.LLVMBuildExtractValue(self.builder, str_val, 0, "str_ptr"); + const ptr = self.extractValue(str_val, 0, "str_ptr"); const idx = try self.genExpr(ie.index); const val = try self.genExpr(asgn.value); const i8_type = self.i8Type(); const gep_ptr = self.gepPointerElement(i8_type, ptr, idx, "stridx"); - const byte_val = c.LLVMBuildTrunc(self.builder, val, i8_type, "trunc_byte"); + const byte_val = self.trunc(val, i8_type, "trunc_byte"); _ = c.LLVMBuildStore(self.builder, byte_val, gep_ptr); return null; } @@ -2827,7 +2885,7 @@ pub const CodeGen = struct { } break :blk try self.genExpr(ie.object); }; - const ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_ptr"); + const ptr = self.extractValue(slice_val, 0, "slice_ptr"); const idx = try self.genExpr(ie.index); const val = try self.genExpr(asgn.value); const gep_ptr = self.gepPointerElement(elem_llvm_ty, ptr, idx, "sliceidx"); @@ -2866,7 +2924,7 @@ pub const CodeGen = struct { .string_literal => |lit| { const content = if (lit.is_raw) lit.raw else try unescape.unescapeString(self.allocator, lit.raw); const str_z = try self.allocator.dupeZ(u8, content); - const ptr = c.LLVMBuildGlobalStringPtr(self.builder, str_z.ptr, "str"); + const ptr = self.buildGlobalString(str_z.ptr, "str"); return self.buildStringSlice(ptr, self.constInt64(@intCast(content.len))); }, .identifier => |ident| { @@ -2925,11 +2983,11 @@ pub const CodeGen = struct { rhs_val = self.loadIfPointer(rhs_val, info.llvm_type, "union_load_r"); // Extract tags (field 0) and compare - const lhs_tag = c.LLVMBuildExtractValue(self.builder, lhs_val, 0, "lhs_tag"); - const rhs_tag = c.LLVMBuildExtractValue(self.builder, rhs_val, 0, "rhs_tag"); + const lhs_tag = self.extractValue(lhs_val, 0, "lhs_tag"); + const rhs_tag = self.extractValue(rhs_val, 0, "rhs_tag"); _ = tag_ty; const pred: c_uint = if (binop.op == .eq) c.LLVMIntEQ else c.LLVMIntNE; - return c.LLVMBuildICmp(self.builder, pred, lhs_tag, rhs_tag, "tag_cmp"); + return self.icmp(pred, lhs_tag, rhs_tag, "tag_cmp"); } const lhs = try self.genExprAsType(binop.lhs, result_type); @@ -3020,7 +3078,7 @@ pub const CodeGen = struct { }, .break_expr => { if (self.loop_break_bb) |break_bb| { - _ = c.LLVMBuildBr(self.builder, break_bb); + self.br(break_bb); _ = self.appendBlock(self.current_function, "after_break"); return null; } @@ -3028,7 +3086,7 @@ pub const CodeGen = struct { }, .continue_expr => { if (self.loop_continue_bb) |continue_bb| { - _ = c.LLVMBuildBr(self.builder, continue_bb); + self.br(continue_bb); _ = self.appendBlock(self.current_function, "after_continue"); return null; } @@ -3057,10 +3115,10 @@ pub const CodeGen = struct { const raw_val = try self.genExpr(val_node); const ret_val = try self.prepareReturnValue(raw_val, self.current_return_type); try self.emitAllDefers(); - _ = c.LLVMBuildRet(self.builder, ret_val); + self.ret(ret_val); } else { try self.emitAllDefers(); - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } _ = self.appendBlock(self.current_function, "after_ret"); return null; @@ -3107,7 +3165,7 @@ pub const CodeGen = struct { } if (obj_ty.isSlice() or obj_ty == .string_type) { const slice_val = try self.genExpr(ie.object); - const ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_ptr"); + const ptr = self.extractValue(slice_val, 0, "slice_ptr"); const elem_ty = if (obj_ty.isSlice()) obj_ty.sliceElementType() orelse return self.emitError("unknown slice element type") else @@ -3124,7 +3182,7 @@ pub const CodeGen = struct { const sname = entry.ty.struct_type; const info = try self.getStructInfo(sname); const idx = try self.findFieldIndex(info.field_names, fa.field, sname); - return c.LLVMBuildStructGEP2(self.builder, info.llvm_type, entry.ptr, @intCast(idx), "addr_field"); + return self.structGEP(info.llvm_type, entry.ptr, @intCast(idx), "addr_field"); } // &u.field where u is a C-style union — all fields at offset 0 if (entry.ty.isUnion()) { @@ -3134,7 +3192,7 @@ pub const CodeGen = struct { } if (info.promoted_fields.get(fa.field)) |pf| { const sinfo = try self.getStructInfo(pf.struct_name); - return c.LLVMBuildStructGEP2(self.builder, sinfo.llvm_type, entry.ptr, @intCast(pf.field_index), "addr_promoted"); + return self.structGEP(sinfo.llvm_type, entry.ptr, @intCast(pf.field_index), "addr_promoted"); } } } @@ -3145,7 +3203,7 @@ pub const CodeGen = struct { const loaded_ptr = c.LLVMBuildLoad2(self.builder, self.ptrType(), entry.ptr, "ptr_load"); const idx = try self.findFieldIndex(info.field_names, fa.field, pointee_name); - return c.LLVMBuildStructGEP2(self.builder, info.llvm_type, loaded_ptr, @intCast(idx), "addr_pfield"); + return self.structGEP(info.llvm_type, loaded_ptr, @intCast(idx), "addr_pfield"); } } } @@ -3550,7 +3608,7 @@ pub const CodeGen = struct { const tag_ty = self.getEnumLLVMType(resolved_name); // Store tag (field 0) — use explicit value if available, otherwise index - const tag_gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, alloca, 0, "tag"); + const tag_gep = self.structGEP(info.llvm_type, alloca, 0, "tag"); const tag_val: u64 = if (self.enum_variant_values.get(resolved_name)) |vals| @bitCast(vals[idx]) else idx; _ = c.LLVMBuildStore(self.builder, c.LLVMConstInt(tag_ty, tag_val, 0), tag_gep); @@ -3672,7 +3730,7 @@ pub const CodeGen = struct { const vec_info = vec_ty.vector_type; const elem_sx_ty = try self.resolveElementType(vec_info.element_name, "vector"); const llvm_vec_ty = self.typeToLLVM(vec_ty); - var vec_val = c.LLVMGetUndef(llvm_vec_ty); + var vec_val = self.getUndef(llvm_vec_ty); const len = @min(al.elements.len, vec_info.length); for (0..len) |i| { @@ -3687,13 +3745,13 @@ pub const CodeGen = struct { const vec_info = vec_ty.vector_type; const llvm_vec_ty = self.typeToLLVM(vec_ty); // Insert scalar at index 0 of undef vector - var vec = c.LLVMGetUndef(llvm_vec_ty); + var vec = self.getUndef(llvm_vec_ty); const zero = self.constInt32(0); vec = c.LLVMBuildInsertElement(self.builder, vec, scalar, zero, "splat_ins"); // Shuffle with zeroinitializer mask to broadcast element 0 to all lanes const mask_ty = c.LLVMVectorType(self.i32Type(), vec_info.length); const mask = c.LLVMConstNull(mask_ty); - return c.LLVMBuildShuffleVector(self.builder, vec, c.LLVMGetUndef(llvm_vec_ty), mask, "splat"); + return c.LLVMBuildShuffleVector(self.builder, vec, self.getUndef(llvm_vec_ty), mask, "splat"); } fn genExprAsType(self: *CodeGen, node: *Node, target_ty: Type) !c.LLVMValueRef { @@ -3716,7 +3774,7 @@ pub const CodeGen = struct { const lit = node.data.string_literal; const content = if (lit.is_raw) lit.raw else try unescape.unescapeString(self.allocator, lit.raw); const str_z = try self.allocator.dupeZ(u8, content); - return c.LLVMBuildGlobalStringPtr(self.builder, str_z.ptr, "str"); + return self.buildGlobalString(str_z.ptr, "str"); } // Enum literal assigned to enum type: resolve variant value @@ -3779,7 +3837,7 @@ pub const CodeGen = struct { .type_expr = null, .field_inits = sl.field_inits, }, payload_struct_name); - const payload_gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, alloca, info.payload_field_index, "payload"); + const payload_gep = self.structGEP(info.llvm_type, alloca, info.payload_field_index, "payload"); const payload_llvm_ty = self.typeToLLVM(variant_ty); const struct_val = c.LLVMBuildLoad2(self.builder, payload_llvm_ty, payload_alloca, "struct_load"); _ = c.LLVMBuildStore(self.builder, struct_val, payload_gep); @@ -3870,7 +3928,7 @@ pub const CodeGen = struct { if (src_ty.isSlice()) { if (std.mem.eql(u8, src_ty.slice_type.element_name, target_ty.many_pointer_type.element_name)) { const slice_val = try self.genExpr(node); - return c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_decay"); + return self.extractValue(slice_val, 0, "slice_decay"); } } } @@ -3955,21 +4013,21 @@ pub const CodeGen = struct { // Any → concrete type: extract the i64 value and convert if (src_ty.isAny()) { - const i64_val = c.LLVMBuildExtractValue(self.builder, val, 1, "any_extract"); + const i64_val = self.extractValue(val, 1, "any_extract"); if (target_ty.isInt()) { if (target_ty.bitWidth() < 64) { - return c.LLVMBuildTrunc(self.builder, i64_val, target_llvm, "any_to_int"); + return self.trunc(i64_val, target_llvm, "any_to_int"); } return i64_val; } if (target_ty == .boolean) { - return c.LLVMBuildTrunc(self.builder, i64_val, self.i1Type(), "any_to_bool"); + return self.trunc(i64_val, self.i1Type(), "any_to_bool"); } if (target_ty == .f64) { - return c.LLVMBuildBitCast(self.builder, i64_val, self.f64Type(), "any_to_f64"); + return self.bitCast(i64_val, self.f64Type(), "any_to_f64"); } if (target_ty == .f32) { - const as_f64 = c.LLVMBuildBitCast(self.builder, i64_val, self.f64Type(), "any_f64_tmp"); + const as_f64 = self.bitCast(i64_val, self.f64Type(), "any_f64_tmp"); return c.LLVMBuildFPTrunc(self.builder, as_f64, self.f32Type(), "any_to_f32"); } if (target_ty == .string_type) { @@ -3985,7 +4043,7 @@ pub const CodeGen = struct { if (target_ty.isEnum()) { const enum_llvm_ty = self.getEnumLLVMType(target_ty.enum_type); const enum_bits = c.LLVMGetIntTypeWidth(enum_llvm_ty); - if (enum_bits < 64) return c.LLVMBuildTrunc(self.builder, i64_val, enum_llvm_ty, "any_to_enum"); + if (enum_bits < 64) return self.trunc(i64_val, enum_llvm_ty, "any_to_enum"); return i64_val; } if (target_ty.isUnion()) { @@ -3995,7 +4053,7 @@ pub const CodeGen = struct { } } if (target_ty.isPointer() or target_ty.isManyPointer()) { - return c.LLVMBuildIntToPtr(self.builder, i64_val, self.ptrType(), "any_to_ptr"); + return self.intToPtr(i64_val, "any_to_ptr"); } return i64_val; } @@ -4029,9 +4087,9 @@ 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, self.i64Type(), "ptrtoint"); + const as_i64 = self.ptrToInt(val, "ptrtoint"); if (target_ty.bitWidth() < 64) { - return c.LLVMBuildTrunc(self.builder, as_i64, target_llvm, "ptr_trunc"); + return self.trunc(as_i64, target_llvm, "ptr_trunc"); } return as_i64; } @@ -4046,8 +4104,8 @@ pub const CodeGen = struct { _ = c.LLVMBuildStore(self.builder, val, tmp); const tag_val = self.loadStructField(info.llvm_type, tmp, 0, tag_llvm_ty); if (target_ty.bitWidth() == tag_bits) return tag_val; - if (target_ty.bitWidth() > tag_bits) return c.LLVMBuildSExt(self.builder, tag_val, target_llvm, "tag_ext"); - return c.LLVMBuildTrunc(self.builder, tag_val, target_llvm, "tag_trunc"); + if (target_ty.bitWidth() > tag_bits) return self.sExt(tag_val, target_llvm, "tag_ext"); + return self.trunc(tag_val, target_llvm, "tag_trunc"); } } @@ -4058,13 +4116,13 @@ pub const CodeGen = struct { if (tw > sw) { // Extend — use SExt if source is signed, ZExt if unsigned if (src_ty.isSigned()) { - return c.LLVMBuildSExt(self.builder, val, target_llvm, "sext"); + return self.sExt(val, target_llvm, "sext"); } else { - return c.LLVMBuildZExt(self.builder, val, target_llvm, "zext"); + return self.zExt(val, target_llvm, "zext"); } } else if (tw < sw) { // Truncate - return c.LLVMBuildTrunc(self.builder, val, target_llvm, "trunc"); + return self.trunc(val, target_llvm, "trunc"); } // Same width, different signedness — no-op (bit pattern is the same) return val; @@ -4072,12 +4130,12 @@ pub const CodeGen = struct { // Int → pointer/function_type: IntToPtr (for xx cast from integer to pointer) if (src_ty.isInt() and (target_ty.isPointer() or target_ty.isManyPointer() or target_ty.isFunctionType())) { - return c.LLVMBuildIntToPtr(self.builder, val, self.ptrType(), "inttoptr"); + return self.intToPtr(val, "inttoptr"); } // Slice/string → pointer: extract .ptr from fat pointer if ((src_ty.isSlice() or src_ty == .string_type) and (target_ty.isPointer() or target_ty.isManyPointer())) { - return c.LLVMBuildExtractValue(self.builder, val, 0, "slice_to_ptr"); + return self.extractValue(val, 0, "slice_to_ptr"); } // Enum → int: extend or truncate from backing type to target int @@ -4085,9 +4143,9 @@ pub const CodeGen = struct { const enum_bits = c.LLVMGetIntTypeWidth(self.getEnumLLVMType(src_ty.enum_type)); const target_bits = target_ty.bitWidth(); if (target_bits > enum_bits) { - return c.LLVMBuildZExt(self.builder, val, target_llvm, "enum_to_int"); + return self.zExt(val, target_llvm, "enum_to_int"); } else if (target_bits < enum_bits) { - return c.LLVMBuildTrunc(self.builder, val, target_llvm, "enum_to_int"); + return self.trunc(val, target_llvm, "enum_to_int"); } return val; } @@ -4098,9 +4156,9 @@ pub const CodeGen = struct { const enum_bits = c.LLVMGetIntTypeWidth(enum_llvm_ty); const src_bits = src_ty.bitWidth(); if (enum_bits > src_bits) { - return c.LLVMBuildZExt(self.builder, val, enum_llvm_ty, "int_to_enum"); + return self.zExt(val, enum_llvm_ty, "int_to_enum"); } else if (enum_bits < src_bits) { - return c.LLVMBuildTrunc(self.builder, val, enum_llvm_ty, "int_to_enum"); + return self.trunc(val, enum_llvm_ty, "int_to_enum"); } return val; } @@ -4183,7 +4241,7 @@ pub const CodeGen = struct { // For Any values: extract the runtime tag (field 0) if (arg_ty.isAny()) { const val = try self.genExpr(arg); - return c.LLVMBuildExtractValue(self.builder, val, 0, "type_of"); + return self.extractValue(val, 0, "type_of"); } // For known types: return the constant tag value @@ -4309,7 +4367,7 @@ pub const CodeGen = struct { // Read tag (field 0) const tag_val = self.loadStructField(uinfo.llvm_type, union_alloca, 0, self.getEnumLLVMType(val_ty.union_type)); - const payload_ptr = c.LLVMBuildStructGEP2(self.builder, uinfo.llvm_type, union_alloca, uinfo.payload_field_index, "fv_payload_ptr"); + const payload_ptr = self.structGEP(uinfo.llvm_type, union_alloca, uinfo.payload_field_index, "fv_payload_ptr"); const n = uinfo.variant_names.len; const any_ty = self.getAnyStructType(); @@ -4320,17 +4378,17 @@ pub const CodeGen = struct { const tag_llvm_ty = self.getEnumLLVMType(val_ty.union_type); for (uinfo.variant_types, 0..) |vty, vi| { - const case_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, "fv_ucase"); + const case_bb = self.appendBB("fv_ucase"); c.LLVMAddCase(sb.sw, c.LLVMConstInt(tag_llvm_ty, @intCast(vi), 0), case_bb); - c.LLVMPositionBuilderAtEnd(self.builder, case_bb); + self.positionAt(case_bb); const any_val = if (vty == .void_type) blk: { // Void variant: return Any with void tag - const undef = c.LLVMGetUndef(any_ty); + const undef = self.getUndef(any_ty); const void_tag = self.constInt64(ANY_TAG_VOID); - const with_tag = c.LLVMBuildInsertValue(self.builder, undef, void_tag, 0, "void_tag"); + const with_tag = self.insertValue(undef, void_tag, 0, "void_tag"); const zero_val = self.constInt64(0); - break :blk c.LLVMBuildInsertValue(self.builder, with_tag, zero_val, 1, "void_any"); + break :blk self.insertValue(with_tag, zero_val, 1, "void_any"); } else blk: { const payload = self.loadTyped(vty, payload_ptr, "fv_payload"); break :blk try self.buildAnyValue(payload, vty); @@ -4339,10 +4397,10 @@ pub const CodeGen = struct { } // Default: undef - c.LLVMPositionBuilderAtEnd(self.builder, sb.default_bb); - try self.addPhiCase(&phi_vals, &phi_bbs, c.LLVMGetUndef(any_ty), sb.merge_bb); + self.positionAt(sb.default_bb); + try self.addPhiCase(&phi_vals, &phi_bbs, self.getUndef(any_ty), sb.merge_bb); - c.LLVMPositionBuilderAtEnd(self.builder, sb.merge_bb); + self.positionAt(sb.merge_bb); const phi = try self.buildPhiNode(&phi_vals, &phi_bbs, any_ty, "fv_uresult"); return phi; } @@ -4354,7 +4412,7 @@ pub const CodeGen = struct { return self.emitErrorFmt("unknown slice element type '{s}'", .{sinfo.element_name}); const elem_llvm_ty = self.typeToLLVM(elem_ty); // val is {ptr, i32} — extract ptr - const data_ptr = c.LLVMBuildExtractValue(self.builder, val, 0, "fv_sdata"); + const data_ptr = self.extractValue(val, 0, "fv_sdata"); const idx = try self.genExpr(call_node.args[1]); const elem_ptr = self.gepPointerElement(elem_llvm_ty, data_ptr, idx, "fv_selem"); const elem = c.LLVMBuildLoad2(self.builder, elem_llvm_ty, elem_ptr, "fv_seval"); @@ -4402,13 +4460,13 @@ pub const CodeGen = struct { var phi_bbs = std.ArrayList(c.LLVMBasicBlockRef).empty; for (0..n) |i| { - const case_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, "fv_case"); + const case_bb = self.appendBB("fv_case"); const case_val = self.constInt64(i); c.LLVMAddCase(sb.sw, case_val, case_bb); - c.LLVMPositionBuilderAtEnd(self.builder, case_bb); + self.positionAt(case_bb); // Extract field i via GEP + load - const field_ptr = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, struct_alloca, @intCast(i), "fv_field_ptr"); + const field_ptr = self.structGEP(info.llvm_type, struct_alloca, @intCast(i), "fv_field_ptr"); const field_llvm_ty = c.LLVMStructGetTypeAtIndex(info.llvm_type, @intCast(i)); const field_val = c.LLVMBuildLoad2(self.builder, field_llvm_ty, field_ptr, "fv_field"); const any_val = try self.buildAnyValue(field_val, info.field_types[i]); @@ -4416,10 +4474,10 @@ pub const CodeGen = struct { } // Default: return undef Any - c.LLVMPositionBuilderAtEnd(self.builder, sb.default_bb); - try self.addPhiCase(&phi_vals, &phi_bbs, c.LLVMGetUndef(any_ty), sb.merge_bb); + self.positionAt(sb.default_bb); + try self.addPhiCase(&phi_vals, &phi_bbs, self.getUndef(any_ty), sb.merge_bb); - c.LLVMPositionBuilderAtEnd(self.builder, sb.merge_bb); + self.positionAt(sb.merge_bb); const phi = try self.buildPhiNode(&phi_vals, &phi_bbs, any_ty, "fv_result"); return phi; } @@ -4455,17 +4513,17 @@ pub const CodeGen = struct { var phi_bbs = std.ArrayList(c.LLVMBasicBlockRef).empty; for (0..n) |i| { - const case_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, "fvi_case"); + const case_bb = self.appendBB("fvi_case"); c.LLVMAddCase(sb.sw, c.LLVMConstInt(i64_type, i, 0), case_bb); - c.LLVMPositionBuilderAtEnd(self.builder, case_bb); + self.positionAt(case_bb); const val: u64 = if (values) |vals| @bitCast(vals[i]) else i; try self.addPhiCase(&phi_vals, &phi_bbs, c.LLVMConstInt(i64_type, val, 0), sb.merge_bb); } - c.LLVMPositionBuilderAtEnd(self.builder, sb.default_bb); + self.positionAt(sb.default_bb); try self.addPhiCase(&phi_vals, &phi_bbs, c.LLVMConstInt(i64_type, 0, 0), sb.merge_bb); - c.LLVMPositionBuilderAtEnd(self.builder, sb.merge_bb); + self.positionAt(sb.merge_bb); const phi = try self.buildPhiNode(&phi_vals, &phi_bbs, i64_type, "fvi_result"); return phi; } @@ -4511,17 +4569,17 @@ pub const CodeGen = struct { } if (is_dup) continue; try seen_values.append(self.allocator, explicit_val); - const case_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, "fi_case"); + const case_bb = self.appendBB("fi_case"); c.LLVMAddCase(sb.sw, c.LLVMConstInt(enum_llvm_ty, explicit_val, 0), case_bb); - c.LLVMPositionBuilderAtEnd(self.builder, case_bb); + self.positionAt(case_bb); try self.addPhiCase(&phi_vals, &phi_bbs, c.LLVMConstInt(i64_type, i, 0), sb.merge_bb); } - c.LLVMPositionBuilderAtEnd(self.builder, sb.default_bb); + self.positionAt(sb.default_bb); const neg_one = c.LLVMConstInt(i64_type, @bitCast(@as(i64, -1)), 0); try self.addPhiCase(&phi_vals, &phi_bbs, neg_one, sb.merge_bb); - c.LLVMPositionBuilderAtEnd(self.builder, sb.merge_bb); + self.positionAt(sb.merge_bb); const phi = try self.buildPhiNode(&phi_vals, &phi_bbs, i64_type, "fi_result"); return phi; } @@ -4605,8 +4663,7 @@ pub const CodeGen = struct { const info = try self.getStructInfo(sname); const idx = self.findNameIndex(info.field_names, fa.field) orelse return self.emitErrorFmt("no field '{s}' in struct '{s}'", .{ fa.field, sname }); - const gep = c.LLVMBuildStructGEP2(self.builder, info.llvm_type, loaded_ptr, - @intCast(idx), "pfield"); + const gep = self.structGEP(info.llvm_type, loaded_ptr, @intCast(idx), "pfield"); return self.loadTyped(info.field_types[idx], gep, "pfieldval"); } if (pointee_ty.isSlice()) { @@ -4674,10 +4731,10 @@ pub const CodeGen = struct { if (entry.ty.isAny()) { const any_val = c.LLVMBuildLoad2(self.builder, self.getAnyStructType(), entry.ptr, "any_load"); if (std.mem.eql(u8, fa.field, "tag")) { - return c.LLVMBuildExtractValue(self.builder, any_val, 0, "any_tag"); + return self.extractValue(any_val, 0, "any_tag"); } if (std.mem.eql(u8, fa.field, "value")) { - return c.LLVMBuildExtractValue(self.builder, any_val, 1, "any_value"); + return self.extractValue(any_val, 1, "any_value"); } return self.emitErrorFmt("no field '{s}' on Any (available: .tag, .value)", .{fa.field}); } @@ -4700,7 +4757,7 @@ pub const CodeGen = struct { const cmp = if (elem_ty.isFloat()) (if (op == .eq) c.LLVMBuildFCmp(self.builder, c.LLVMRealOEQ, lhs, rhs, "vcmp") else c.LLVMBuildFCmp(self.builder, c.LLVMRealONE, lhs, rhs, "vcmp")) else - (if (op == .eq) c.LLVMBuildICmp(self.builder, c.LLVMIntEQ, lhs, rhs, "vcmp") else c.LLVMBuildICmp(self.builder, c.LLVMIntNE, lhs, rhs, "vcmp")); + (if (op == .eq) self.icmp(c.LLVMIntEQ, lhs, rhs, "vcmp") else self.icmp(c.LLVMIntNE, lhs, rhs, "vcmp")); // Reduce: extract each i1 and AND (eq) or OR (neq) var result = c.LLVMBuildExtractElement(self.builder, cmp, self.constInt32(0), "cmp0"); for (1..vec_info.length) |i| { @@ -4742,7 +4799,7 @@ pub const CodeGen = struct { if (obj_ty == .string_type) { // 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 ptr = self.extractValue(str_val, 0, "str_ptr"); const idx = try self.genExpr(ie.index); const i8_type = self.i8Type(); const gep = self.gepPointerElement(i8_type, ptr, idx, "stridx"); @@ -4757,7 +4814,7 @@ pub const CodeGen = struct { if (ie.object.data == .identifier) { if (self.named_values.get(ie.object.data.identifier.name)) |entry| { const slice_val = c.LLVMBuildLoad2(self.builder, self.getStringStructType(), entry.ptr, "slice_load"); - const ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_ptr"); + const ptr = self.extractValue(slice_val, 0, "slice_ptr"); const idx = try self.genExpr(ie.index); const gep = self.gepPointerElement(elem_llvm_ty, ptr, idx, "sliceidx"); return c.LLVMBuildLoad2(self.builder, elem_llvm_ty, gep, "sliceval"); @@ -4765,7 +4822,7 @@ pub const CodeGen = struct { } // Fallback for non-identifier slice expressions const slice_val = try self.genExpr(ie.object); - const ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "slice_ptr"); + const ptr = self.extractValue(slice_val, 0, "slice_ptr"); const idx = try self.genExpr(ie.index); const gep = self.gepPointerElement(elem_llvm_ty, ptr, idx, "sliceidx"); return c.LLVMBuildLoad2(self.builder, elem_llvm_ty, gep, "sliceval"); @@ -4823,8 +4880,8 @@ pub const CodeGen = struct { } break :blk try self.genExpr(se.object); }; - const base_ptr = c.LLVMBuildExtractValue(self.builder, obj_val, 0, "sslice_ptr"); - const base_len = c.LLVMBuildExtractValue(self.builder, obj_val, 1, "sslice_len"); + const base_ptr = self.extractValue(obj_val, 0, "sslice_ptr"); + const base_len = self.extractValue(obj_val, 1, "sslice_len"); // Resolve end (default: original length) const end_val = if (se.end) |e| try self.genExpr(e) else base_len; // GEP base_ptr + start @@ -4877,29 +4934,27 @@ pub const CodeGen = struct { } fn genShortCircuitOp(self: *CodeGen, binop: ast.BinaryOp, is_and: bool) !c.LLVMValueRef { - const function = self.current_function; - const lhs_val = self.valueToBool(try self.genExpr(binop.lhs)); - const lhs_bb = c.LLVMGetInsertBlock(self.builder); + const lhs_bb = self.getCurrentBlock(); const rhs_label: [*c]const u8 = if (is_and) "and.rhs" else "or.rhs"; const merge_label: [*c]const u8 = if (is_and) "and.merge" else "or.merge"; - const rhs_bb = c.LLVMAppendBasicBlockInContext(self.context, function, rhs_label); - const merge_bb = c.LLVMAppendBasicBlockInContext(self.context, function, merge_label); + const rhs_bb = self.appendBB(rhs_label); + const merge_bb = self.appendBB(merge_label); // AND: true → evaluate rhs, false → short-circuit to merge // OR: true → short-circuit to merge, false → evaluate rhs if (is_and) - _ = c.LLVMBuildCondBr(self.builder, lhs_val, rhs_bb, merge_bb) + self.condBr(lhs_val, rhs_bb, merge_bb) else - _ = c.LLVMBuildCondBr(self.builder, lhs_val, merge_bb, rhs_bb); + self.condBr(lhs_val, merge_bb, rhs_bb); - c.LLVMPositionBuilderAtEnd(self.builder, rhs_bb); + self.positionAt(rhs_bb); const rhs_val = self.valueToBool(try self.genExpr(binop.rhs)); - const rhs_end_bb = c.LLVMGetInsertBlock(self.builder); - _ = c.LLVMBuildBr(self.builder, merge_bb); + const rhs_end_bb = self.getCurrentBlock(); + self.br(merge_bb); - c.LLVMPositionBuilderAtEnd(self.builder, merge_bb); + self.positionAt(merge_bb); const short_circuit_val: u64 = if (is_and) 0 else 1; const result_label: [*c]const u8 = if (is_and) "and.result" else "or.result"; const i1_ty = self.i1Type(); @@ -5197,7 +5252,7 @@ pub const CodeGen = struct { } else if (llvm_param_is_ptr and arg_ty == .string_type) blk: { // String variable → pointer: extract .ptr from {ptr, len} const str_val = try self.genExpr(arg); - break :blk c.LLVMBuildExtractValue(self.builder, str_val, 0, "str_ptr"); + break :blk self.extractValue(str_val, 0, "str_ptr"); } else if ((param_ty.isPointer() or llvm_param_is_ptr) and arg_ty.isSlice() and std.mem.eql(u8, arg_ty.slice_type.element_name, "u8")) { @@ -5266,7 +5321,7 @@ pub const CodeGen = struct { } else if (pt == .string_type) { // [:0]u8 params: extract .ptr from fat pointer const val = try self.genExprAsType(arg, pt); - try arg_vals.append(self.allocator, c.LLVMBuildExtractValue(self.builder, val, 0, "str_ptr")); + try arg_vals.append(self.allocator, self.extractValue(val, 0, "str_ptr")); } else { try arg_vals.append(self.allocator, try self.genExprAsType(arg, pt)); } @@ -5590,7 +5645,7 @@ pub const CodeGen = struct { } // Extract Any value i64 BEFORE the switch (switch is a terminator, nothing can follow it in the same BB) - const any_i64 = c.LLVMBuildExtractValue(self.builder, any_val, 1, "any_payload"); + const any_i64 = self.extractValue(any_val, 1, "any_payload"); // Build dispatch switch const sb = self.buildSwitch(type_tag_val, @intCast(match_tags.len), "dispatch_merge", "dispatch_default"); @@ -5616,9 +5671,9 @@ pub const CodeGen = struct { const sx_type = entry_type orelse continue; // Create case BB - const case_bb = c.LLVMAppendBasicBlockInContext(self.context, self.current_function, "dispatch_case"); + const case_bb = self.appendBB("dispatch_case"); c.LLVMAddCase(sb.sw, self.constInt64(tag), case_bb); - c.LLVMPositionBuilderAtEnd(self.builder, case_bb); + self.positionAt(case_bb); // Convert Any payload to the concrete type const concrete_val = try self.extractAnyToConcreteType(any_i64, sx_type); @@ -5693,21 +5748,21 @@ pub const CodeGen = struct { if (ret_ty != .void_type) { try phi_vals.append(self.allocator, call_result); - try phi_bbs.append(self.allocator, c.LLVMGetInsertBlock(self.builder)); + try phi_bbs.append(self.allocator, self.getCurrentBlock()); } - _ = c.LLVMBuildBr(self.builder, sb.merge_bb); + self.br(sb.merge_bb); } // Default case: return undef (should not be reached) - c.LLVMPositionBuilderAtEnd(self.builder, sb.default_bb); + self.positionAt(sb.default_bb); if (ret_ty != .void_type and result_llvm_ty != null) { - try phi_vals.append(self.allocator, c.LLVMGetUndef(result_llvm_ty.?)); + try phi_vals.append(self.allocator, self.getUndef(result_llvm_ty.?)); try phi_bbs.append(self.allocator, sb.default_bb); } - _ = c.LLVMBuildBr(self.builder, sb.merge_bb); + self.br(sb.merge_bb); // Merge - c.LLVMPositionBuilderAtEnd(self.builder, sb.merge_bb); + self.positionAt(sb.merge_bb); if (ret_ty != .void_type and result_llvm_ty != null) { const phi = try self.buildPhiNode(&phi_vals, &phi_bbs, result_llvm_ty.?, "dispatch_phi"); return phi; @@ -5719,20 +5774,20 @@ pub const CodeGen = struct { /// Extract a concrete typed value from an Any i64 payload. fn extractAnyToConcreteType(self: *CodeGen, any_i64: c.LLVMValueRef, sx_type: Type) !c.LLVMValueRef { return switch (sx_type) { - .boolean => c.LLVMBuildTrunc(self.builder, any_i64, self.i1Type(), "any_to_bool"), + .boolean => self.trunc(any_i64, self.i1Type(), "any_to_bool"), .signed => |w| if (w <= 32) - c.LLVMBuildTrunc(self.builder, any_i64, c.LLVMIntTypeInContext(self.context, w), "any_to_int") + self.trunc(any_i64, c.LLVMIntTypeInContext(self.context, w), "any_to_int") else any_i64, .unsigned => |w| if (w <= 32) - c.LLVMBuildTrunc(self.builder, any_i64, c.LLVMIntTypeInContext(self.context, w), "any_to_uint") + self.trunc(any_i64, c.LLVMIntTypeInContext(self.context, w), "any_to_uint") else any_i64, .f32 => blk: { - const as_f64 = c.LLVMBuildBitCast(self.builder, any_i64, self.f64Type(), "i64_to_f64"); + const as_f64 = self.bitCast(any_i64, self.f64Type(), "i64_to_f64"); break :blk c.LLVMBuildFPTrunc(self.builder, as_f64, self.f32Type(), "any_to_f32"); }, - .f64 => c.LLVMBuildBitCast(self.builder, any_i64, self.f64Type(), "any_to_f64"), + .f64 => self.bitCast(any_i64, self.f64Type(), "any_to_f64"), .string_type => self.loadFromI64Ptr(any_i64, self.getStringStructType(), "any_to_str"), .struct_type => |sname| blk: { const info = try self.getStructInfo(sname); @@ -5742,7 +5797,7 @@ pub const CodeGen = struct { const enum_llvm_ty = self.getEnumLLVMType(ename); const enum_bits = c.LLVMGetIntTypeWidth(enum_llvm_ty); if (enum_bits < 64) - break :blk c.LLVMBuildTrunc(self.builder, any_i64, enum_llvm_ty, "any_to_enum") + break :blk self.trunc(any_i64, enum_llvm_ty, "any_to_enum") else break :blk any_i64; }, @@ -5755,7 +5810,7 @@ pub const CodeGen = struct { break :blk self.loadFromI64Ptr(any_i64, llvm_ty, "any_to_vec"); }, .slice_type => self.loadFromI64Ptr(any_i64, self.getStringStructType(), "any_to_slice"), - .pointer_type, .many_pointer_type => c.LLVMBuildIntToPtr(self.builder, any_i64, self.ptrType(), "any_to_ptr"), + .pointer_type, .many_pointer_type => self.intToPtr(any_i64, "any_to_ptr"), else => any_i64, }; } @@ -5807,7 +5862,7 @@ pub const CodeGen = struct { // Save current codegen state const saved_function = self.current_function; const saved_return_type = self.current_return_type; - const saved_insert_bb = c.LLVMGetInsertBlock(self.builder); + const saved_insert_bb = self.getCurrentBlock(); // Save named_values var saved_named_values = std.StringHashMap(NamedValue).init(self.allocator); @@ -5896,20 +5951,20 @@ pub const CodeGen = struct { } // Emit return if current block has no terminator - const current_bb = c.LLVMGetInsertBlock(self.builder); + const current_bb = self.getCurrentBlock(); if (c.LLVMGetBasicBlockTerminator(current_bb) == null) { if (ret_sx_type == .void_type) { - _ = c.LLVMBuildRetVoid(self.builder); + self.retVoid(); } else if (last_val) |val| { if (ret_sx_type.isStruct()) { const sname = ret_sx_type.struct_type; const info = try self.getStructInfo(sname); const loaded = c.LLVMBuildLoad2(self.builder, info.llvm_type, val, "retval"); - _ = c.LLVMBuildRet(self.builder, loaded); + self.ret(loaded); } else { const src_ty = self.llvmTypeToSxType(c.LLVMTypeOf(val)); const converted = self.convertValue(val, src_ty, ret_sx_type); - _ = c.LLVMBuildRet(self.builder, converted); + self.ret(converted); } } else { _ = c.LLVMBuildUnreachable(self.builder); @@ -5920,7 +5975,7 @@ pub const CodeGen = struct { self.current_function = saved_function; self.current_return_type = saved_return_type; if (saved_insert_bb) |bb| { - c.LLVMPositionBuilderAtEnd(self.builder, bb); + self.positionAt(bb); } self.named_values.clearRetainingCapacity(); var restore_iter = saved_named_values.iterator(); @@ -5940,36 +5995,35 @@ pub const CodeGen = struct { // Generate condition const cond_val = self.valueToBool(try self.genExpr(if_expr.condition)); - const function = self.current_function; const has_else = if_expr.else_branch != null; - var then_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "then"); + var then_bb = self.appendBB("then"); var else_bb: c.LLVMBasicBlockRef = if (has_else) - c.LLVMAppendBasicBlockInContext(self.context, function, "else") + self.appendBB("else") else null; - const merge_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "merge"); + const merge_bb = self.appendBB("merge"); const false_dest = if (has_else) else_bb else merge_bb; - _ = c.LLVMBuildCondBr(self.builder, cond_val, then_bb, false_dest); + self.condBr(cond_val, then_bb, false_dest); // Then branch - c.LLVMPositionBuilderAtEnd(self.builder, then_bb); + self.positionAt(then_bb); const then_val = try self.genExpr(if_expr.then_branch); - then_bb = c.LLVMGetInsertBlock(self.builder); // may have changed due to nested control flow - _ = c.LLVMBuildBr(self.builder, merge_bb); + then_bb = self.getCurrentBlock(); // may have changed due to nested control flow + self.br(merge_bb); // Else branch var else_val: c.LLVMValueRef = null; if (if_expr.else_branch) |else_branch| { - c.LLVMPositionBuilderAtEnd(self.builder, else_bb); + self.positionAt(else_bb); else_val = try self.genExpr(else_branch); - else_bb = c.LLVMGetInsertBlock(self.builder); - _ = c.LLVMBuildBr(self.builder, merge_bb); + else_bb = self.getCurrentBlock(); + self.br(merge_bb); } // Merge block - c.LLVMPositionBuilderAtEnd(self.builder, merge_bb); + self.positionAt(merge_bb); // PHI node if both branches produced values if (then_val != null and else_val != null) { @@ -5984,24 +6038,22 @@ pub const CodeGen = struct { } fn genWhileExpr(self: *CodeGen, while_expr: ast.WhileExpr) !c.LLVMValueRef { - const function = self.current_function; - // Create basic blocks: condition, body, after - const cond_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "while.cond"); - const body_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "while.body"); - const after_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "while.after"); + const cond_bb = self.appendBB("while.cond"); + const body_bb = self.appendBB("while.body"); + const after_bb = self.appendBB("while.after"); // Branch from current block to condition check - _ = c.LLVMBuildBr(self.builder, cond_bb); + self.br(cond_bb); // Condition block - c.LLVMPositionBuilderAtEnd(self.builder, cond_bb); + self.positionAt(cond_bb); const cond_val = self.valueToBool(try self.genExpr(while_expr.condition)); - _ = c.LLVMBuildCondBr(self.builder, cond_val, body_bb, after_bb); + self.condBr(cond_val, body_bb, after_bb); // Body block — save and set loop context for break/continue - c.LLVMPositionBuilderAtEnd(self.builder, body_bb); + self.positionAt(body_bb); const saved_break_bb = self.loop_break_bb; const saved_continue_bb = self.loop_continue_bb; self.loop_break_bb = after_bb; @@ -6014,19 +6066,18 @@ pub const CodeGen = struct { self.loop_continue_bb = saved_continue_bb; // Branch back to condition (if not already terminated by break/return) - const current_bb = c.LLVMGetInsertBlock(self.builder); + const current_bb = self.getCurrentBlock(); if (c.LLVMGetBasicBlockTerminator(current_bb) == null) { - _ = c.LLVMBuildBr(self.builder, cond_bb); + self.br(cond_bb); } // Position at after block - c.LLVMPositionBuilderAtEnd(self.builder, after_bb); + self.positionAt(after_bb); return null; } fn genForExpr(self: *CodeGen, for_expr: ast.ForExpr) !c.LLVMValueRef { - const function = self.current_function; const i64_type = self.i64Type(); // Determine iterable type and get length + element access info @@ -6044,8 +6095,8 @@ pub const CodeGen = struct { if (for_expr.iterable.data == .identifier) { if (self.named_values.get(for_expr.iterable.data.identifier.name)) |entry| { const slice_val = c.LLVMBuildLoad2(self.builder, self.getStringStructType(), entry.ptr, "for_slice"); - iter_ptr = c.LLVMBuildExtractValue(self.builder, slice_val, 0, "for_ptr"); - len_val = c.LLVMBuildExtractValue(self.builder, slice_val, 1, "for_len"); + iter_ptr = self.extractValue(slice_val, 0, "for_ptr"); + len_val = self.extractValue(slice_val, 1, "for_len"); } else return self.emitError("for: iterable not found"); } else return self.emitError("for: slice iterable must be a variable"); } else if (iter_ty.isArray()) { @@ -6075,20 +6126,20 @@ pub const CodeGen = struct { 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"); - const body_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "for.body"); - const after_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "for.after"); + const cond_bb = self.appendBB("for.cond"); + const body_bb = self.appendBB("for.body"); + const after_bb = self.appendBB("for.after"); - _ = c.LLVMBuildBr(self.builder, cond_bb); + self.br(cond_bb); // Condition: it_index < len - c.LLVMPositionBuilderAtEnd(self.builder, cond_bb); + self.positionAt(cond_bb); 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); + const cond_val = self.icmp(c.LLVMIntSLT, cur_idx, len_val, "for_cond"); + self.condBr(cond_val, body_bb, after_bb); // Body: load it = iterable[it_index], then execute body - c.LLVMPositionBuilderAtEnd(self.builder, body_bb); + self.positionAt(body_bb); const body_idx = c.LLVMBuildLoad2(self.builder, i64_type, idx_alloca, "body_idx"); if (is_slice) { @@ -6118,15 +6169,15 @@ pub const CodeGen = struct { self.loop_continue_bb = saved_continue_bb; // Increment it_index - const current_bb = c.LLVMGetInsertBlock(self.builder); + const current_bb = self.getCurrentBlock(); if (c.LLVMGetBasicBlockTerminator(current_bb) == null) { 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); + self.br(cond_bb); } - c.LLVMPositionBuilderAtEnd(self.builder, after_bb); + self.positionAt(after_bb); try self.popScope(); @@ -6186,16 +6237,15 @@ pub const CodeGen = struct { else null; - const function = self.current_function; const i64_type = self.i64Type(); // Enum/union case constants use the backing type; Any dispatch uses i64 const case_int_type = if (enum_name) |en| self.getEnumLLVMType(en) else if (union_name) |un| self.getEnumLLVMType(un) else i64_type; - const merge_bb = c.LLVMAppendBasicBlockInContext(self.context, function, "match_end"); + const merge_bb = self.appendBB("match_end"); // Create case basic blocks var case_bbs = std.ArrayList(c.LLVMBasicBlockRef).empty; for (match.arms) |_| { - try case_bbs.append(self.allocator, c.LLVMAppendBasicBlockInContext(self.context, function, "case")); + try case_bbs.append(self.allocator, self.appendBB("case")); } // Find else arm (null pattern) — use its BB as the switch default @@ -6209,7 +6259,7 @@ pub const CodeGen = struct { const default_bb = if (else_arm_idx) |idx| case_bbs.items[idx] else - c.LLVMAppendBasicBlockInContext(self.context, function, "match_default"); + self.appendBB("match_default"); // Build switch instruction const sw = c.LLVMBuildSwitch(self.builder, subject_val, default_bb, @intCast(match.arms.len)); @@ -6255,14 +6305,14 @@ pub const CodeGen = struct { } for (match.arms, 0..) |arm, i| { - c.LLVMPositionBuilderAtEnd(self.builder, case_bbs.items[i]); + self.positionAt(case_bbs.items[i]); if (arm.is_break) { - _ = c.LLVMBuildBr(self.builder, merge_bb); + self.br(merge_bb); } else if (arm.pattern != null and arm_tag_values.items[i].len == 0 and (arm.pattern.?.data == .identifier or arm.pattern.?.data == .type_expr)) { // Category/type arm with no matching types — BB is unreachable, skip body - _ = c.LLVMBuildBr(self.builder, merge_bb); + self.br(merge_bb); } else { // Payload capture: bind variant payload as a local variable if (arm.capture) |cap_name| { @@ -6279,7 +6329,7 @@ pub const CodeGen = struct { const variant_ty = uinfo.variant_types[vi]; if (variant_ty != .void_type) { const subject_entry = self.named_values.get(match.subject.data.identifier.name).?; - const payload_gep = c.LLVMBuildStructGEP2(self.builder, uinfo.llvm_type, subject_entry.ptr, uinfo.payload_field_index, "cap_payload"); + const payload_gep = self.structGEP(uinfo.llvm_type, subject_entry.ptr, uinfo.payload_field_index, "cap_payload"); const payload_llvm_ty = self.typeToLLVM(variant_ty); const payload_val = c.LLVMBuildLoad2(self.builder, payload_llvm_ty, payload_gep, "cap_load"); const cap_alloca = c.LLVMBuildAlloca(self.builder, payload_llvm_ty, @ptrCast(cap_name.ptr)); @@ -6295,8 +6345,8 @@ pub const CodeGen = struct { self.current_match_tags = arm_tag_values.items[i]; const val = try self.genExpr(arm.body); self.current_match_tags = saved_match_tags; - const bb = c.LLVMGetInsertBlock(self.builder); - _ = c.LLVMBuildBr(self.builder, merge_bb); + const bb = self.getCurrentBlock(); + self.br(merge_bb); if (val != null and c.LLVMGetTypeKind(c.LLVMTypeOf(val)) != c.LLVMVoidTypeKind) { has_value = true; if (value_type == null) value_type = c.LLVMTypeOf(val); @@ -6308,15 +6358,15 @@ pub const CodeGen = struct { // Default block branches to merge (only if no else arm — else arm's body already generated above) if (else_arm_idx == null) { - c.LLVMPositionBuilderAtEnd(self.builder, default_bb); - _ = c.LLVMBuildBr(self.builder, merge_bb); + self.positionAt(default_bb); + self.br(merge_bb); } // Merge block - c.LLVMPositionBuilderAtEnd(self.builder, merge_bb); + self.positionAt(merge_bb); if (has_value and value_type != null) { - const undef_val = c.LLVMGetUndef(value_type); + const undef_val = self.getUndef(value_type); // Add undef entries for break arms and default block for (match.arms, 0..) |arm, i| { if (arm.is_break) { @@ -6444,7 +6494,7 @@ pub const CodeGen = struct { /// Resolve a builtin parameterized type (e.g. Vector(3, f32)). /// Strips namespace prefix to get base name, then dispatches. fn resolveBuiltinType(self: *CodeGen, name: []const u8, args: []const *Node) ?Type { - const base = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; + const base = baseName(name); if (std.mem.eql(u8, base, "Vector")) { if (args.len >= 2) { const n: u32 = @intCast(self.resolveValueArg(args[0])); @@ -6473,7 +6523,7 @@ pub const CodeGen = struct { fn dispatchBuiltin(self: *CodeGen, name: []const u8, call_node: ast.Call) !c.LLVMValueRef { // Extract base name (strip namespace prefix) - const base = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; + const base = baseName(name); if (std.mem.eql(u8, base, "write")) return self.genWriteCall(call_node.args); if (std.mem.eql(u8, base, "sqrt")) return self.genMathIntrinsic(call_node, "sqrt"); if (std.mem.eql(u8, base, "sin")) return self.genMathIntrinsic(call_node, "sin"); @@ -6500,11 +6550,11 @@ pub const CodeGen = struct { const builtins = try self.requireBuiltins(); 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_i64 = c.LLVMBuildExtractValue(self.builder, val, 1, "str_len"); + const ptr = self.extractValue(val, 0, "str_ptr"); + const len_i64 = self.extractValue(val, 1, "str_len"); // printf %.*s precision is C int (i32) — truncate from i64 - const len = c.LLVMBuildTrunc(self.builder, len_i64, self.i32Type(), "len_trunc"); - const fmt = c.LLVMBuildGlobalStringPtr(self.builder, "%.*s", "write_fmt"); + const len = self.trunc(len_i64, self.i32Type(), "len_trunc"); + const fmt = self.buildGlobalString("%.*s", "write_fmt"); const printf_fn = builtins.printf_fn; const fn_type = c.LLVMGlobalGetValueType(printf_fn); var call_args = [_]c.LLVMValueRef{ fmt, len, ptr }; @@ -6515,7 +6565,7 @@ pub const CodeGen = struct { /// Helper: build a constant string slice in the current function fn buildConstStr(self: *CodeGen, s: []const u8) c.LLVMValueRef { const sz = self.allocator.dupeZ(u8, s) catch unreachable; - const ptr = c.LLVMBuildGlobalStringPtr(self.builder, sz.ptr, "cstr"); + const ptr = self.buildGlobalString(sz.ptr, "cstr"); return self.buildStringSlice(ptr, self.constInt64(@intCast(s.len))); } @@ -6702,7 +6752,7 @@ pub const CodeGen = struct { if (obj_ty) |uty| return uty; } 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; + const base_name = baseName(callee_name); // Built-in: sqrt/sin/cos returns same type as argument if (std.mem.eql(u8, base_name, "sqrt") or std.mem.eql(u8, base_name, "sin") or diff --git a/src/comptime.zig b/src/comptime.zig index c687282..bb18d7a 100644 --- a/src/comptime.zig +++ b/src/comptime.zig @@ -3,6 +3,10 @@ const types = @import("types.zig"); const Type = types.Type; const unescape = @import("unescape.zig"); +fn baseName(name: []const u8) []const u8 { + return if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; +} + /// Runtime value for comptime evaluation. /// Replaces codegen's JitResult with richer type support. pub const Value = union(enum) { @@ -651,7 +655,7 @@ pub const Compiler = struct { if (callee_name) |name| { // Check if it's a builtin - const base = if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; + const base = baseName(name); if (std.meta.stringToEnum(BuiltinId, base)) |id| { try self.emit(.{ .call_builtin = .{ .id = id, .arg_count = @intCast(call_node.args.len) } }); } else { diff --git a/src/sema.zig b/src/sema.zig index c3c900c..cca5f87 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -6,6 +6,10 @@ const Type = @import("types.zig").Type; const errors = @import("errors.zig"); const Diagnostic = errors.Diagnostic; +fn baseName(name: []const u8) []const u8 { + return if (std.mem.lastIndexOfScalar(u8, name, '.')) |idx| name[idx + 1 ..] else name; +} + pub const SymbolKind = enum { variable, constant, @@ -344,7 +348,7 @@ pub const Analyzer = struct { return sig.return_type; } // Built-in: sqrt/sin/cos returns same type as argument - const base = if (std.mem.lastIndexOfScalar(u8, callee_name, '.')) |idx| callee_name[idx + 1 ..] else callee_name; + const base = baseName(callee_name); if (std.mem.eql(u8, base, "sqrt") or std.mem.eql(u8, base, "sin") or std.mem.eql(u8, base, "cos"))